10

我了解了 swing 不是线程安全的。深入研究后,我发现对 Swing 组件的每次修改都必须在 Event Dispatch Thread 上完成,以防止与多线程相关的各种问题。然而,信息似乎完全停在那里。似乎没有一个很好的教程来解释如何在互联网上任何可访问的地方执行此操作。

将发布的与其他问题相关的代码中的信息拼凑在一起,似乎我必须在我的程序中的每一个摆动修改周围放置一个不整洁的代码块(就像我自己的代码中的这个示例):

try {
        SwingUtilities.invokeAndWait(new Runnable() {

            public void run() {
                setTitle("Frame title");
                setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                setVisible(true);

                setSize(800, 480);
                setLocationRelativeTo(null);
                setIconImage(Toolkit.getDefaultToolkit().createImage(ClassLoader.getSystemResource("Frame icon.png")));
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }

基本上,这是对的吗?我是否必须在代码中对 Swing 组件的每次修改都放置该代码(或与 invokeLater 等效的代码)?

另外,为什么 Swing 不自动执行此操作?

4

4 回答 4

8

诀窍是当 swing 呼叫你时,它总是在 EDT,所以你不必担心。

但是,如果您处于计时器或由其他外部事件、主线程或您创建的任何其他线程触发的操作中,那么是的,您必须使用 invokeLater 或 invokeAndWait。

换句话说,是的,swing 确实会自动执行“它”。需要使用invokeXx 的情况非常少见,如果swing 在内部使用它会浪费太多时间。

许多 Java 程序员从来没有弄清楚这一点,它可能会在绘制 GUI 时导致一些非常讨厌的难以发现的问题。当你调用它而不使用 EDT 时,我确实希望 Swing 抛出一个异常——如果这样做的话,Java 在专业 GUI 方面会有更好的声誉,因为那里的废话会更少。

于 2011-10-25T22:58:01.067 回答
4

请注意,从事件处理程序执行的任何代码都已在 EDT 中运行(首字母缩略词中的事件)

这意味着对于一般用途(虽然您不会与 swingworkers 和线程池等混淆),您总是在 EDT 内

并且您可以随时查询您是否在 EDT 中SwingUtilities.isEventDispatchThread()

另请注意,在您的代码中,invokeAndWait当您已经在 EDT 中时,调用将失败并引发错误

于 2011-10-25T22:58:37.930 回答
3

基本上,您不会从 EDT 外部绘制或更新 GUI。您使用来自另一个线程的 SwingUtilitis.invokeLater() 来确保在 EDT 上运行 GUI 绘图或更新代码。

于 2011-10-25T22:45:58.530 回答
3

并非所有 UI 代码都必须是 invokeLater 调用中可运行的一部分。这仅仅是因为您的程序的很大一部分无论如何都将在 EDT 上运行。只有当您在不同的线程上时,您才需要向 EDT 发送消息。

于 2011-10-25T22:59:50.703 回答