3

我有一个程序,我正在加载文件,同时我正在显示一个窗口以通知用户正在加载文件。我决定创建一个 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(),但这需要对我的代码进行一些我不想做的修改。

谁能告诉我最好的方法是让它工作吗?

4

3 回答 3

6

get()就像join()它会阻塞直到被调用,并在被调用之前等待 SwingWorker 完成。首先错误地使用它会完全抵消使用 SwingWorker 的所有优势。

get()解决方案:在您知道 SwingWorker 完成处理之前不要调用,方法是在 SwingWorker 的done()方法中调用它,或者如果您需要从调用代码中调用它,则在已添加到 SwingWorker 的 PropertyChangeListener 中调用当 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");

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

编辑:添加了尝试/捕获。

于 2012-07-18T18:14:01.713 回答
3

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

如果您调用SwingUtilities.invokeLater()将在 EDT 中执行冻结 GUI 的线程的线程。相反,通过调用它的start()方法来运行线程,并且仅SwingUtilities.invokeLater()在需要更新PropertyChangeListener.

于 2012-07-18T18:05:55.553 回答
0

我已经创建了一个 WorkerThread 类来处理 Threads 和 GUI current/main thread 。当事件触发以启动 XXXServer 时,我已将我的 GUI 应用程序放入 WorkerThread 的construct() 方法中,然后所有线程都被激活并且 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());
    }

}
于 2014-12-23T12:25:32.163 回答