如何从 JButton ActionListener 调用重算法
How to call a heavy algorithm from JButton ActionListener
我正在编写一个既充当服务器又充当客户端的 Java 程序。忽略不相关的位,它有三个 类:Main、Server 和 Client。 Main 只是设置一个菜单并包含 main 方法。 Server和Client分别保存了服务器端和客户端的算法。
我想做的是根据按下的按钮从服务器和客户端 类 及其 GUI 调用算法。调用服务器的代码目前如下所示:
serverButton = new JButton();
serverButton.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
server.showGUI();
server.run();
}
});
问题是 server.run()
连续运行了很长一段时间,而且工作量很大。这会破坏 GUI,据我了解,这是因为我正在从 EDT 调用该方法。
如何从主线程调用这个方法?我是否需要创建一个 SwingWorker
并将其留在那里直到 server.run() 结束?
确保服务器对象引用是最终的,然后在 actionPerformed 方法的新线程中调用该方法。
Runnable task = () -> {server.run();};
Thread thread = new Thread(task);
thread.start();
这取决于您的要求,如果您希望用户在服务器 returns 之前不想做任何事情,最好在 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()
{
}
});
}
});
请注意,这不是线程侦听器的完整代码,仅供参考。
How can I call this method from the main thread?
这是 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);
}
}
This bugs out the GUI, which from my understanding is because I'm
calling the method from the EDT.
是的,由于操作是由事件触发的,因此 actionPerformed() 由 EDT(或在 EDT 上)调用。我不知道你在 server.run() 中做什么,但我想这不应该出现在 EDT 上。
Do I need to create a SwingWorker and leave it there until the end of
server.run()?
在这种情况下,我会使用 SwingWorker 或 SwingUtilities。您可以使用两个线程以这种方式编写一个 ActionHandler,一个用于执行某些 'heavy lifting',一个用于设置 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
});
}
}
我正在编写一个既充当服务器又充当客户端的 Java 程序。忽略不相关的位,它有三个 类:Main、Server 和 Client。 Main 只是设置一个菜单并包含 main 方法。 Server和Client分别保存了服务器端和客户端的算法。
我想做的是根据按下的按钮从服务器和客户端 类 及其 GUI 调用算法。调用服务器的代码目前如下所示:
serverButton = new JButton();
serverButton.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
server.showGUI();
server.run();
}
});
问题是 server.run()
连续运行了很长一段时间,而且工作量很大。这会破坏 GUI,据我了解,这是因为我正在从 EDT 调用该方法。
如何从主线程调用这个方法?我是否需要创建一个 SwingWorker
并将其留在那里直到 server.run() 结束?
确保服务器对象引用是最终的,然后在 actionPerformed 方法的新线程中调用该方法。
Runnable task = () -> {server.run();};
Thread thread = new Thread(task);
thread.start();
这取决于您的要求,如果您希望用户在服务器 returns 之前不想做任何事情,最好在 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()
{
}
});
}
});
请注意,这不是线程侦听器的完整代码,仅供参考。
How can I call this method from the main thread?
这是 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);
}
}
This bugs out the GUI, which from my understanding is because I'm calling the method from the EDT.
是的,由于操作是由事件触发的,因此 actionPerformed() 由 EDT(或在 EDT 上)调用。我不知道你在 server.run() 中做什么,但我想这不应该出现在 EDT 上。
Do I need to create a SwingWorker and leave it there until the end of server.run()?
在这种情况下,我会使用 SwingWorker 或 SwingUtilities。您可以使用两个线程以这种方式编写一个 ActionHandler,一个用于执行某些 'heavy lifting',一个用于设置 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
});
}
}