繁体   English   中英

如何从JButton 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM