【问题标题】:What to put (and not to put) inside SwingUtilities.invokeLater?在 SwingUtilities.invokeLater 中放置(而不是放置)什么?
【发布时间】:2016-06-07 09:59:03
【问题描述】:

在 Swing-land 中,从静态主方法中调用 SwingUtilities.invokeLater(Runnable) 似乎是一种常见/良好的做法:

public class MyApp extends JFrame {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            void run() {
                // What to do here?!?
            }
        });

        // And what to do here?!?
    }
}

根据那个方法的JavaDocs

导致 doRun.run() 在 AWT 事件调度线程上异步执行。这将在处理完所有待处理的 AWT 事件后发生。当应用程序线程需要更新 GUI 时,应使用此方法。在以下示例中,invokeLater 调用将 Runnable 对象 doHelloWorld 在事件调度线程上排队,然后打印一条消息。

但即使在阅读了这篇文章之后,我仍然对在这个 Runnable(我们传递给 invokeLater)中放入什么(具体)代码以及什么代码感到困惑放在里面。有什么想法吗?

【问题讨论】:

  • In 可以直接或间接地以某种方式更改 UI 或与 UI 交互的任何内容,外部可以进行任何其他操作,尤其是任何阻塞或长时间运行的代码
  • 感谢@MadProgrammer (+1) - 您是否有机会通过一些简单的代码示例更新您的评论以作为答案?例如,当您说“in go things that may change the UI...”时,您能举几个具体的例子吗?
  • "你能举几个具体的例子吗?" - 如果它可能以任何方式(直接或间接)改变 UI。一般的经验法则是将任何基于 Swing 的组件视为非线程安全的,并且您不应该有任何问题,开始第二次猜测此规则,您将遇到麻烦,也许不是今天,但很可能是明天。
  • however in that link you posted neither the term "SwingUtilities" nor "Concurrency" show up in any search - 这个想法是让您查看“目录”(顶部的“Trail”链接)以查看 Swing 教程中的“所有”部分。您会发现该主题以及其他有助于解决未来问题的 Swing 主题。

标签: java multithreading swing awt


【解决方案1】:

我认为camickr已经基本回答了核心问题

要(大部分)重新迭代,输入任何可能直接或间接改变 UI 或以某种方式与 UI 交互的内容,外部可以进行任何其他操作,尤其是任何阻塞或长时间运行的代码

如果您看过我的任何与 Swing 相关的答案,您就会看到这种模板(是的,这是我在 Netbeans 中设置的代码模板)

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}

你能举几个具体的例子吗?

如果它可能以任何方式改变 UI(直接或间接 - 更改组件的属性,更新布局等)。一般的经验法则是将任何基于 Swing 的组件视为非线程安全的,并且您不应该有任何问题,开始重新猜测此规则,您将遇到麻烦,也许不是今天,但很可能是明天。

问题是,当组件可能触发对 EDT 的更新时,API 中几乎没有保证,这是您真正关心的问题。如有疑问,请放入 EDT。

API 中被认为是线程安全的方法很少,repaint 是最明显的,但就我个人而言,我只是将整个 API 视为不是线程安全的,这样就省去了很多猜测。

如果您知道您有一个长时间运行或可能阻塞的操作(文件 IO、网络调用等),那么这些操作需要在 EDT 之外进行(可能使用 SwingWorker 或 Swing Timer 作为合适),但是当您想要更新 UI(例如更改标签的文本或更新进度条)时,必须在 EDT 的上下文中进行这些调用。

首先仔细看看Concurrency in Swing

【讨论】:

  • I think camickr has basically answered the core concerns - 显然不是。显然教程代码不能完成这项工作。答案已删除。
  • @camickr 我会留下它的,没关系,我为我的社区创建了一个 wiki,以免竞争......真的不想回答所有问题
【解决方案2】:

对于未来的人,我想通了,尽管文档并没有以对 Swing 新手来说显而易见的方式真正解释这一点:

  • 当文档或博客/文章/人们说“任何与 UI 接触的东西”时,这将转换为:“任何对 javax.swing.* 下的 Swing 类的操作 ”。因此,用JFrameJPanelJComponents 中的任何一个做任何事情。所有这些东西都应该在您从应用程序的main 方法内部传递给SwingUtilities.invokeLaterRunnable 中执行。所以基本上你最终会得到一个巨大的、整体的Runnable,它可以完成所有的 UI 代码操作。奇怪和反 MVC 恕我直言。
  • 如果您有一个长时间运行的进程,您应该从该进程中删除所有 Swing 代码并将其传递给您自己的 SwingWorker

【讨论】:

    猜你喜欢
    • 2012-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-09
    • 1970-01-01
    相关资源
    最近更新 更多