我们是否应该在Java桌面应用程序中使用EventQueue.invokeLater进行任何GUI更新?

时间:2010-08-22 11:53:40

标签: java swing thread-safety

我知道通过使用此方法,runnable参数将提交给系统EventQueue。 但是,如果使用此方法完成所有GUI更新吗?我的意思是,如果我想说,改变一个JButton的文本,我应该使用这样的东西:

java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
         jButton1.setText("changed text");
      }
});

如果我应该使用这种方法,我们可以使用任何模式来避免这种重复的代码?

3 个答案:

答案 0 :(得分:26)

当您想要从不是UI线程的另一个线程(事件调度线程)更新UI时,您只需要使用invokeLater

假设您有按钮单击的处理程序,并且您希望在有人单击按钮时更改标签的文本。然后直接设置标签文本就完全可以了。这是可能的,因为按钮单击事件的处理程序在UI线程中运行。

但是,假设在另一个按钮上单击启动另一个执行某些工作的线程,在完成此工作后,您需要更新UI。然后使用invokeLater。此方法可确保在UI线程上执行UI更新。

因此,在很多情况下,您不需要invokeLater,您可以直接进行UI更新。如果您不确定,可以使用isDispatchThread检查当前代码是否在事件派发线程内运行。

答案 1 :(得分:2)

只有当您尚未使用事件派发线程时,才需要执行此操作。除非您已经从主线程启动了新线程或执行了代码,否则所有代码可能已经从事件派发线程运行,这使得这不必要。例如,在事件调度线程上调用所有UI事件处理程序,因此您不需要为从那里调用的代码执行此操作。

答案 2 :(得分:1)

您可以使用Eclipse的模板功能,而不是真正避免“重复”(java人可能会说,没有很多秘密的可读代码)。我将它设置为将两个字母“il”扩展到以下块:

EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    // do something.
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

显然这个调度队列设计不仅是推荐的,基本上也是必需的。这可能是我用任何语言将lambda推送到消息队列中的最嘈杂的方式。但它确实如此。这是java。在Java的辩护中,从上面的确切情况来看,它确实显而易见。我不满意打字的数量,但我唯一能想到的就是避免它是C预处理器宏,我打赌Java人不喜欢使用它们。通过模板进行代码扩展更具可读性,可支持性,并且不涉及任何黑魔法。