当GUI不更新信息时,使用多线程处理带有SWING的GUI

时间:2011-01-25 22:34:06

标签: java multithreading swing

所以我有一个使用受this tutorial启发的MVC模式设计的桌面应用程序(但略有修改)。此应用程序需要做的是将文件列表从目录复制到另一个目录。我想做的是基本上在复制每个文件后更新我的GUI。

首先让我告诉你代码。 在我的模型中,我有这种虚拟方法(不是真正的方法,但背后的逻辑是相同的):

public void dummyMethod(Integer k) throws InterruptedException{
    for(int i=0;i<10;i++){
        System.out.println(i);
    Thread.sleep(1000);
        this.firePropertyChange(DefaultController.BACKUP_DUMMY, i-1, i);
    }
}

在我看来,我有这个:

@Override
    public void modelPropertyChange(PropertyChangeEvent evt) {
        // .......


        else if( evt.getPropertyName().equals( DefaultController.BACKUP_DUMMY ) ){
            System.out.println("WHAT?");
            this.dummy.setText(evt.getNewValue().toString());
        }

    }

你可以想象每次打印 WHAT?但是在循环结束之前GUI不会更新。 这是你使用SWING及其EDT时的经典问题,我在oracle网站上阅读了article/tutorial,但我认为我不需要使用SwingWorker。我只需更新GUI上的单个组件。

2 个答案:

答案 0 :(得分:3)

  

但是在循环结束之前GUI不会更新。

这表示您的所有代码都在EDT上运行,因此GUI在整个循环结束之前无法重新绘制。

  

但我认为我不需要使用SwingWorker。

为什么不,这可能是最简单的解决方案。您可以在单独的线程上运行主循环,然后在处理每个文件时“发布”结果。

或者使用Gursel建议的方法。长时间运行的代码在一个单独的线程中执行,只有属性更改事件的触发在EDT上,这意味着GUI可以在EDT上重新绘制自己。

答案 1 :(得分:1)

不要将事件调度线程用于长时间运行的操作。您应该为长时间运行的操作启动另一个线程,例如文件复制。如果需要从工作线程更新gui,则应使用SwingUtilities.invokeLater或SwingUtilities.invokeAndWait方法..

作为例子;

final JLabel label = new JLabel();
JButton button = new JButton();
button.addActionListener(new ActionListener() {
    public void actioPerformed(ActionEvent ev) {
         Thread workerThread = new Thread() {
               public void run() {
                     //do long running job then update ui
                   SwingUtilities.invokeLater(new Runnable() {
                           public void run(){
                               label.setText("Operation has finished");
                           }
                    });

               }
         }.start();    
    }
});