6

我有一个简单的 groovy 脚本,从它的主线程执行需要向用户显示一些对话框。

我的挥杆知识有限且生疏,但我记得读过有关需要小心地将 GUI 内容保留在事件调度线程 (EDT) 上的信息。

如果我只是从我的主线程调用静态JOptionPane.showMessageDialog方法,我是否正确地假设这会违反将 GUI 内容保存在 EDT 上的正确做法?

我真的应该使用 swing.utils.invokeAndWait 方法,例如下面的示例代码吗?


void showHelloThereDialog() 
        throws Exception {
    Runnable showModalDialog = new 
      Runnable() {
        public void run() {
            JOptionPane.showMessageDialog(
               myMainFrame, "Hello There");
        }
    };
    SwingUtilities.invokeAndWait
       (showModalDialog);
}

现在,在 invokeAndWait 完成后,除了消息对话框之外,上面的内容没有做任何事情来使值可用。

据推测,groovy 'closures' 实现 Runnable 将使代码比上面更简单。

是否需要 invokeAndWait?如果是这样,有人请举一个正确实现的例子来获得类似使用groovy的confirmDialog之类的结果吗?

4

3 回答 3

8

JOptionPane对showXXXDialog()之一的调用是阻塞的,直到用户选择 ok/cancel/etc。一般来说,您通常不会在事件调度线程 (EDT) 上放置如此缓慢的阻塞指令,因为每个其他 GUI 组件都会冻结。所以,不把它放在 EDT 上的直觉是好的,但它也是错误的。原因正如其他人所说,该方法创建 GUI 组件,这应该始终在 EDT 上完成。但是阻塞呢?您会注意到,即使您确实在 EDT 上运行它,它也能正常工作。原因在源代码中找到。该类JOptionPane创建一个 Dialog 对象,然后调用show()dispose()其中第一个是阻塞线程的。如果您阅读评论(或 javadoc),您会看到它说明了该方法:

如果对话框是模态的并且尚不可见,则此调用将不会返回,直到通过调用 hide 或 dispose 隐藏对话框。允许从事件调度线程显示模式对话框,因为工具包将确保另一个事件泵运行,而调用此方法的事件泵被阻塞。

JOptionPane因此,尽管它被阻塞,但在 EDT上运行是完全安全的。显然,show()在 EDT 之外调用 Dialog 的方法是安全的,但情况并非如此,JOptionPane因为它的方法是创建 GUI 组件、添加侦听器、在模态时访问其他容器并阻止对它们的输入等等。你不想要所有这些完成了 EDT,因为它不是线程安全的并且可能存在问题。诚然,我在 EDT 外使用时从未遇到过问题JOptionPane,因此可能性似乎很低,但它们肯定是有可能的。为对话框的容器传入一个 null 并且只给出不可变的对象(比如Strings)作为字段的参数将显着减少(据我所知甚至可能消除)发生不良事件的可能性,因为所有相关的 GUI 组件都是在同一个线程中制作和访问的,而它们不可见。但是,您应该安全并将其放在 EDT 上。调用起来并不难SwingUtilities.invokeAndWait()

于 2012-07-21T04:59:34.433 回答
5

这应该在 EDT 上,因此需要 invokeAndWait 或 invokeLater。您可以看出,因为 JOptionPane.showMessageDialog 的代码最终会创建和修改 Swing 组件。从 Java 6 开始,Sun 表示 Swing 组件的所有操作(无论它们是否已实现)都必须在 EDT 上完成。

http://download.oracle.com/javase/6/docs/api/javax/swing/package-summary.html

http://www.velocityreviews.com/forums/t707173-why-does-jdk-1-6-recommend-creating-swing-components-on-the-edt.html

于 2011-03-30T20:37:44.477 回答
4

看一下groovy.swing.SwingBuilder,它封装了invokeAndWait和invokeLater。你的例子可以写成:

import groovy.swing.SwingBuilder
import javax.swing.*
import java.awt.*

def swing = new SwingBuilder()
def myMainFrame = new Frame()

swing.edt {
    JOptionPane.showMessageDialog(
        myMainFrame, "Hello There");
}
于 2011-03-30T20:58:21.613 回答