java 使用 invokeLater 或 SwingWorker 从另一个线程更新 Swing 组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2247703/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 20:17:25  来源:igfitidea点击:

Updating Swing component from another thread with invokeLater or SwingWorker

javaswingmultithreading

提问by Mil

I'm developing a small app, which would have Swing GUI. App is doing IO task in another thread, when that thread finishes GUI should be updated acordingly to reflect thread's operation result. Class running in a (worker, non-GUI) has object passed to it in contructor which would be used for updating GUI, so I don't need to put GUI stuff in a non-GUI class, but rather pass object for updating GUI to that class. As I understand form reading here, (thread/swing) safe options for updating (changing) Swing GUI would be to use javax.swing.SwingUtilities.invokeLater(), javax.swing.SwingUtilities.invokeLaterWait()and/or javax.swing.SwingWorker()which basically are doing the same thing.

我正在开发一个带有 Swing GUI 的小应用程序。应用程序正在另一个线程中执行 IO 任务,当该线程完成时,应相应更新 GUI 以反映线程的操作结果。在 (worker, non-GUI) 中运行的类在构造函数中传递给它的对象将用于更新 GUI,所以我不需要将 GUI 的东西放在非 GUI 类中,而是传递用于更新 GUI 的对象到那个班级。正如我在这里理解的形式阅读,用于更新(更改)Swing GUI 的(线程/摆动)安全选项将使用javax.swing.SwingUtilities.invokeLater()javax.swing.SwingUtilities.invokeLaterWait()和/或javax.swing.SwingWorker()基本上做同样的事情。

This all threading issue with Swing is a little confusing for me, and yet I need to use threads to do anything meaningful in GUI apps and not hung GUI while processing in EDT, so what interests me for now is this:

Swing 的所有线程问题让我有点困惑,但我需要使用线程在 GUI 应用程序中做任何有意义的事情,而不是在 EDT 中处理时挂起 GUI,所以我现在感兴趣的是:

  1. Are invokeLaterand invokeLaterWaitlike sending message to EDT and waiting for it do it when it finishes processing messages that were before that call?

  2. is it correct from Swing thread safety aspect, to do something like this:

    interface IUPDATEGUI {  
      public void update();  
    }  
    
    // in EDT/where I can access components directly    
    class UpdateJList implements IUPDATEGUI {    
      public void update() {    
        // update JList...    
        someJList.revalidate();    
        someJList.repain();    
      }    
    }    
    
    class FileOperations implements Runnable {  
      private IUPDATEGUI upObj;  
      List<File> result = new ArrayList<File>; // upObject is accessing this  
    
      public void FileOperations(IUPDATEGUI upObj) {
        this.upObj = upObj;
      }
    
      private void someIOTask() {
        // ...
        // IO processing finished, result is in "result"
      }
    
      public void run() {
        someIOTask();
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            upObj.update();  // access result and update JList
          }
        }; );
      }
    }
    
  1. invokeLaterinvokeLaterWait如发送消息,美国东部时间并等待它做它时,它完成将原本调用之前处理消息?

  2. 从 Swing 线程安全方面来看,这样做是否正确:

    interface IUPDATEGUI {  
      public void update();  
    }  
    
    // in EDT/where I can access components directly    
    class UpdateJList implements IUPDATEGUI {    
      public void update() {    
        // update JList...    
        someJList.revalidate();    
        someJList.repain();    
      }    
    }    
    
    class FileOperations implements Runnable {  
      private IUPDATEGUI upObj;  
      List<File> result = new ArrayList<File>; // upObject is accessing this  
    
      public void FileOperations(IUPDATEGUI upObj) {
        this.upObj = upObj;
      }
    
      private void someIOTask() {
        // ...
        // IO processing finished, result is in "result"
      }
    
      public void run() {
        someIOTask();
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            upObj.update();  // access result and update JList
          }
        }; );
      }
    }
    

In case this isn't correct then how should this be done?

如果这不正确,那么应该如何做?

If I could, I would prefer to use invokeLaterinstead of SwingWorkerif possible, because I wouldn't need to change my whole class and it's somehow more neat/distinct me (like sending a message in Win32 apps).

如果可以的话,我宁愿使用invokeLater而不是SwingWorker如果可能的话,因为我不需要改变我的整个班级,而且它在某种程度上更整洁/与众不同(比如在 Win32 应用程序中发送消息)。

Thanks in advance.

提前致谢。

回答by Savvas Dalkitsis

Using invokeLater()and invokeAndWait()passes the Runnable parameter into the queue awaiting execution in the EDT. So calling invokeLater()will cause the Runnable to execute in the EDT when the EDT is able to process the request. invokeAndWait()simply waits (in the calling thread) until this execution takes place.

使用invokeLater()invokeAndWait()传递的Runnable参数到在EDT队列等待执行。因此invokeLater(),当 EDT 能够处理请求时,调用将导致 Runnable 在 EDT 中执行。invokeAndWait()只是等待(在调用线程中)直到执行发生。

Using SwingWorker is ideal if you want to do background tasks that notify the EDT either at the end of execution or in intermediate states. An example would be to pass the current progress of a process to a JProgressBar.

如果您想要在执行结束时或在中间状态执行通知 EDT 的后台任务,则使用 SwingWorker 是理想的选择。一个例子是将进程的当前进度传递给 JProgressBar。

For your example it seems that SwingWorker is a better choice but if you don't want to change your code too much then calling invokeLater()when the process is done will be just fine.

对于您的示例,似乎 SwingWorker 是一个更好的选择,但是如果您不想过多地更改代码,那么invokeLater()在流程完成时调用就可以了。

回答by reccles

I'd recommend not using the invokeAndWait until java 7. I found a spurious wake-up on this method that can cause really painful bugs. For me it led to some really rare and hard to debug null pointer exceptions.

我建议在 java 7 之前不要使用 invokeAndWait。我发现这种方法的虚假唤醒会导致非常痛苦的错误。对我来说,它导致了一些非常罕见且难以调试的空指针异常。

http://bugs.sun.com/view_bug.do?bug_id=6852111

http://bugs.sun.com/view_bug.do?bug_id=6852111

It's fixed as of java 7 b77.

它从 java 7 b77 开始修复。

回答by Chris Jester-Young

invokeLateris fine. This puts the call into the AWT event queue, so that it will get executed in the EDT in due course. Your program will continue running, and does not wait for your callable to get called.

invokeLater很好。这会将调用放入 AWT 事件队列,以便在适当的时候在 EDT 中执行。您的程序将继续运行,并且不会等待您的可调用对象被调用。