调用SwingWorker.get()时防止GUI冻结

时间:2012-07-18 18:01:19

标签: java swing swingworker

我有一个程序,我正在加载文件,同时我正在显示一个窗口,通知用户文件正在加载。我决定创建一个FileLoader类,它实际上是处理加载文件的SwingWorker和一个实现PropertyChangeListener的ProgressWindow,以告知用户传递给它的SwingWorker的状态。

我的代码目前看起来像这样:

FileLoader loader = new FileLoader(filePath);
new ProgressWindow(loader, "Loading File", "Loading File");
//ProgressWindow's constructor calls loader.execute() inherited from SwingWorker
doc = loader.get(); //GUI Freezes when called

问题在于,无论何时我调用loader.get(),它都会冻结GUI,因此进度窗口中的进度条不会运行,整个过程毫无意义。据我所知,这是因为控制GUI的线程与调用loader.get()的线程是相同的,当loader.execute()运行时,该线程会被保留。

到目前为止,我已经尝试为loader.get()命令或loader.execute()方法创建一个新线程,并在线程上调用SwingUtilities.invokeLater(),但随后整个程序冻结。

我考虑过为SwingWorker.isDone()创建一个ChangeListener,然后运行loader.get(),但这需要对我的代码进行一些修改,而我宁愿不做。

有人能告诉我最好的方法是让它发挥作用吗?

3 个答案:

答案 0 :(得分:6)

get()join()类似,它会在被调用之前阻塞,并等待SwingWorker在被调用之前完成。错误地使用它可以完全取消使用SwingWorker的所有优点。

解决方案:在您知道SwingWorker完成其处理后,通过在SwingWorker的get()方法中调用它,或者如果您需要从调用中调用它,请不要调用done()代码,然后在SwingWorker的“state”属性为SwingWorker.StateValue.DONE时已添加到SwingWorker的PropertyChangeListener中。

类似的东西:

  final FileLoader loader = new FileLoader(filePath);

  loader.addPropertyChangeListener(new PropertyChangeListener() {
     @Override
     public void propertyChange(PropertyChangeEvent evt) {
        if ("state".equals(evt.getPropertyName())) {
           // since DONE is enum, no need for equals(...) method
           if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
              try {
                 loader.get();
              } catch (InterruptedException e) {
                 e.printStackTrace();
              } catch (ExecutionException e) {
                 e.printStackTrace();
              }
           }
        }
     }
  });

  new ProgressWindow(loader, "Loading File", "Loading File");

注意:代码未编译也未经过测试

编辑:尝试/捕捉添加。

答案 1 :(得分:3)

  

到目前为止,我已经尝试为loader.get()命令或loader.execute()方法创建一个新线程,并在线程上调用SwingUtilities.invokeLater(),但随后整个程序冻结。

如果在将执行EDT中冻结GUI的线程的线程上调用SwingUtilities.invokeLater()。相反,通过调用它的start()方法运行该线程,并在需要更新SwingUtilities.invokeLater()中的进度条时仅使用PropertyChangeListener

答案 2 :(得分:0)

我创建了一个WorkerThread类来处理Threads和GUI current / main thread。 我已经将我的GUI应用程序放在WorkerThread的construct()方法中,当一个事件触发启动XXXServer然后所有线程都被激活并且GUI工作平稳地没有冻结。看看。

/**
* Action Event
* 
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent ae) {
    log.info("actionPerformed begin..." + ae.getActionCommand());

    try {
        if (ae.getActionCommand().equals(btnStart.getText())) {
             final int portNumber = 9990;
             try {

                 WorkerThread workerThread = new WorkerThread(){
                    public Object construct(){

                        log.info("Initializing the Server GUI...");
                        // initializing the Server
                         try {
                            xxxServer = new XXXServer(portNumber);
                            xxxServer.start();
                            btnStart.setEnabled(false);                             
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            log.info("actionPerformed() Start button ERROR IOEXCEPTION..." + e.getMessage());
                            e.printStackTrace();
                        }
                        return null;
                    }
                };workerThread.start();
                } catch (Exception e) {
                    log.info("actionPerformed() Start button ERROR..." + e.getMessage());
                    e.printStackTrace();
             }


        } else if (ae.getActionCommand().equals(btnStop.getText())) {
            log.info("Exit..." + btnStop.getText());
            closeWindow();
        }

    } catch (Exception e) {
        log
            .info("Error in ServerGUI actionPerformed==="
                + e.getMessage());
    }

}