![](/img/trans.png)
[英]How to remove JButton from JFrame from inside JButton's ActionListener?
[英]How to call a heavy algorithm from JButton ActionListener
我正在编写一个既充当服务器又充当客户端的Java程序。 忽略不相关的位,它具有三个类别:Main,Server和Client。 Main只是设置一个菜单并包含main方法。 服务器和客户端分别持有服务器和客户端的算法。
我想要做的是根据所按下的按钮从服务器和客户端类及其GUI调用算法。 当前调用服务器的代码如下:
serverButton = new JButton();
serverButton.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
server.showGUI();
server.run();
}
});
问题是server.run()
连续运行了很长一段时间,而且繁重。 这使GUI出错,据我了解,这是因为我正在从EDT调用该方法。
如何从主线程调用此方法? 我是否需要创建一个SwingWorker
并将其保留到server.run()结束?
如何从主线程调用此方法?
这是通常在Swing中完成的方式。
public class WhatEverServer {
private UserInterface userInterface;
[...]
private static void createAndShowGUI() {
if( GraphicsEnvironment.isHeadless() )
logger.log( Level.FATAL, "This system seems to be 'headless'. Aborting now." );
else {
userInterface = UserInterface.getInstance();
userInterface.createAndShowUI();
}
}
public static void main( String[] args ) {
// schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater( new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
public class UserInterface {
...
public void createAndShowUI() {
// make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
// create and set up the window.
JFrame frame = new JFrame( "Whatever Server" );
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// set UI components, i.e
// set main menu bar
frame.setJMenuBar( this.mainMenuBar );
// set layout
frame.getContentPane().setLayout( new BorderLayout() );
// add UI components
// display the window.
frame.pack();
frame.setVisible(true);
}
}
这使GUI出错,据我了解,这是因为我正在从EDT调用该方法。
是的,由于操作是由事件触发的,因此EDT(或在EDT上)会调用actionPerformed()。 我不知道您在server.run()中做什么,但是我想这不应该在EDT上结束。
我是否需要创建一个SwingWorker并将其保留到server.run()结束?
在这种情况下,我将使用SwingWorker或SwingUtilities。 您可以以这种方式编写ActionHandler,使用两个线程,一个用于执行某些“繁重的工作”,一个用于设置UI:
public void actionPerformed(ActionEvent e) {
new Thread(new Runnable {
public void run() {
...
// do some 'heavy lifting' here ...
SwingUtilities.invokeLater(new Runnable() {
public void run() {
server.setupUI();
}
)
...
// or do some 'heavy lifting' here
});
}
}
确保服务器对象引用是最终的,然后在actionPerformed方法的新线程中调用该方法。
Runnable task = () -> {server.run();};
Thread thread = new Thread(task);
thread.start();
这取决于您的要求,如果您希望用户在服务器返回之前不希望做任何事情,最好在Busyindicator
中执行Busyindicator
:
public void actionPerformed( ActionEvent e )
{
BusyIndicator.showWhile(Display.getCurrent(), new Runnable()
{
@Override
public void run()
{
server.run();
}
});
}
这将在服务器运行进行中向用户显示一个沙漏,并且阻止用户使用UI。
要么
如果希望UI响应,则需要在单独的线程中调用server.run()
。
MyThread t = new MyThread()
{
public void run()
{
server.run();
}
}
t.start();
最好在线程中添加侦听器以通知服务器响应完成,以便UI可以执行其操作。
t.addListener( new MyThreadListener()
{
public void serverDone()
{
Display.getDefault().asyncExec( new Runnable()
{
public void run()
{
}
});
}
});
请注意,出于主意考虑,这不是用于线程侦听器的完整代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.