Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在调用SwingWorker.get()时防止GUI冻结_Java_Swing_Swingworker - Fatal编程技术网

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

Java 在调用SwingWorker.get()时防止GUI冻结,java,swing,swingworker,Java,Swing,Swingworker,我有一个程序,在加载文件的同时显示一个窗口,通知用户正在加载文件。我决定创建一个FileLoader类,它是一个实际处理加载文件的SwingWorker,以及一个实现PropertyChangeListener的ProgressWindow,以通知用户传递给它的SwingWorker的状态 我的代码当前如下所示: FileLoader loader = new FileLoader(filePath); new ProgressWindow(loader, "Loading File", "Lo

我有一个程序,在加载文件的同时显示一个窗口,通知用户正在加载文件。我决定创建一个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(),但随后整个程序冻结

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

有谁能告诉我,最好的办法是什么

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

如果在将在EDT中执行线程的线程上调用
SwingUtilities.invokeLater()
,将冻结GUI。相反,通过调用它的
start()
方法来运行线程,并且只在需要更新
PropertyChangeListener
中的进度条时使用
SwingUtilities.invokeLater()
get()
类似于
join()
,因为它会一直阻塞,直到被调用为止,并将等待SwingWorker完成后再被调用。错误地使用它首先会完全抵消使用SwingWorker的所有优势

解决方案:在知道SwingWorker的处理完成之前,不要调用它,方法是在SwingWorker的
done()
方法中调用它,或者如果需要从调用代码中调用它,则在SwingWorker的“状态”为属性为SwingWorker.StateValue.DONE

比如:

  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");
注意:代码未编译或测试


编辑:添加try/catch。

我创建了一个WorkerThread类,负责线程和GUI当前/主线程。 我已经将我的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());
    }

}

不幸的是,我不能在done()期间调用get(),因为我需要将get()的结果返回给调用方法,而done()不返回任何内容。而PropertyChangeListener正是我希望避免的事情,但我认为这可能是必要的。为什么要避免呢?编写代码很容易,如果需要调用get(),这是必要的。它只需要在程序的另一部分重写代码,但我认为这是必要的。这也意味着我必须在更多的地方编写更多的代码。我希望有一个很好的封装解决方案。@Thunderforge您读过SwingWorker API吗???publish()或process(),btw API描述了正确的解决方案,包括代码我已经尝试过处理这个问题,但由于线程无法返回值,所以我没有找到一个好方法来实现它。您可以改为在线程之外修改值。或者如果你真的需要一个返回值,使用一个线程。我喜欢FutureTask的想法,但是我很难让我的头脑集中在它上面。谢谢