何时何地调用 EventQueue.invokeLater() 方法

When and Where to call EventQueue.invokeLater() method

我对线程和 GUI 完全陌生,因此我无法确定在何处调用此 EventQueue.invokeLater() 方法。

我应该在每个事件侦听器中调用它吗?调用此方法的那些 "things" 是什么?如果是这样,是否有任何替代方法来调用一次应用到所有地方的方法,这样它就不会花费大量的行来将它们塞进事件调度线程?

谢谢。

therefore I couldn't figure out exactly where to call this EventQueue.invokeLater() method.

Swing 组件需要在 EDT 上更新,因此如果您在单独的线程中执行代码并且想要更新 GUI 组件,则只能使用 invokeLater(...)。

阅读 Concurrency 上的 Swing 教程部分了解更多信息。

作为一般规则,除非您正在使用线程,否则您只需要在创建 GUI 时使用此方法。查看 Swing 教程中 How to Make Frames 部分的 FrameDemo 以获取简单示例以帮助您入门。

Am I supposed to call it in every event listeners?

没有!

事件处理程序中的所有代码都已在 Event Dispatch Thread (EDT) 上执行,因此您无需调用此方法。

Swing 不是线程安全的。这意味着与 Swing 对象的所有交互都应通过事件线程完成。 Swing 也在内部执行此操作,因此任何时候 Swing 调用事件侦听器时,都将在事件线程上完成。

这意味着两件事,首先,如果您需要与 Swing 对象交互,您的代码应该在事件调度程序线程上调用。

此外,这意味着如果您的事件侦听器中有任何代码将 运行 持续任何明显的时间段,则应在侦听器的另一个线程上调用。如果您不这样做,那么您的 UI 将被冻结。 SwingWorker 对象可以帮助解决这个问题。

回答您在一些现有答案的评论中提出的关于需要检查 EventQueue.isDispatchThread() 的问题:

不,您不必在致电 invokeLater() 之前检查您是否已经在美国东部时间。

SwingUtilities JavaDoc 状态:

If invokeLater is called from the event dispatching thread -- for example, from a JButton's ActionListener -- the doRun.run() will still be deferred until all pending events have been processed. Note that if the doRun.run() throws an uncaught exception the event dispatching thread will unwind (not the current thread).

下面是invokeLater()使用的进一步解释。

注意 ButtonDemo.java 中使用 invokeLater() 调用了 createAndShowGUI()。我们必须这样做,因为 main() 方法不是 EDT(事件调度线程)上的 运行。 main() 运行 在每个 Java 应用程序都有的自己的特殊主线程上。

public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
}

然而在actionPerformed()中,invokeLater()方法没有被使用,因为这里我们已经在EDT

//b1, b2, and b3 are all JButtons
public void actionPerformed(ActionEvent e) {
    if ("disable".equals(e.getActionCommand())) {
        b2.setEnabled(false);
        b1.setEnabled(false);
        b3.setEnabled(true);
    } else {
        b2.setEnabled(true);
        b1.setEnabled(true);
        b3.setEnabled(false);
    }
}

据我所知,actionPerformed() 等事件侦听器方法总是从 EDT 调用。 (抱歉,我不知道手边的支持文档,而且我还没有足够的声誉来 post 链接。除了阅读 camickr 答案中链接的页面外,尝试 Google 搜索"java tutorial swing introduction event listeners".)

因此,如果您尝试从 EDT 以外的线程更新 Swing 组件,请调用 invokeLater()。如果您在事件侦听器方法中(即已经在 EDT 上),则无需调用 invokeLater().