【问题标题】:When and Where to call EventQueue.invokeLater() method何时何地调用 EventQueue.invokeLater() 方法
【发布时间】:2015-02-23 15:52:14
【问题描述】:

我对线程和 GUI 完全陌生,因此我不知道在哪里调用这个 EventQueue.invokeLater() 方法。

我应该在每个事件侦听器和其他东西中调用它吗?调用此方法的那些“东西”是什么?如果是这样,是否有任何替代方法来调用一次应用无处不在的方法,这样它就不会花很多行来将它们塞进事件调度线程?

谢谢。

【问题讨论】:

  • @Anto 谢谢你的链接,但是,我想要具体的例子来展示这个方法的真实用法。另外,我想问一下是否有捷径可以轻松完成这个调用过程。

标签: java multithreading swing event-dispatch-thread code-duplication


【解决方案1】:

因此,我无法确定在何处调用此 EventQueue.invokeLater() 方法。

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

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

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

我应该在每个事件监听器中调用它吗?

不!

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

【讨论】:

  • 好吧,我想再问一件事,如果我们已经知道 EDT 发生在哪里,我们什么时候应该像这样检查if(EventQueue.isDispatchThread())?(在这种情况下,我们编写的代码是摆动的) .
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

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

    不,您不必在致电invokeLater() 之前检查您是否已经在 EDT。

    SwingUtilities JavaDoc 声明:

    如果从事件分派线程调用​​ invokeLater ——例如,从 JButton 的 ActionListener —— doRun.run() 仍将被延迟,直到所有未决事件都已处理完毕。请注意,如果 doRun.run() 抛出未捕获的异常,则事件调度线程将展开(而不是当前线程)。

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

    注意ButtonDemo.java 中的 createAndShowGUI() 是使用 invokeLater() 调用的。我们必须这样做,因为 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 调用。 (抱歉,我不知道手头的支持文档,而且我还没有足够的声誉来发布更多链接。除了阅读 camickr 答案中链接的页面外,请尝试 Google 搜索“java tutorial swing introduction event listeners” .)

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

    【讨论】:

      猜你喜欢
      • 2022-11-25
      • 1970-01-01
      • 2015-01-08
      • 2011-04-26
      • 1970-01-01
      • 1970-01-01
      • 2013-03-13
      • 2011-09-06
      • 1970-01-01
      相关资源
      最近更新 更多