什么是JOptionPane.showMessageDialog和swing.utils.invokeAndWait的(事件调度)线程安全用法?

Ale*_*ard 6 java groovy user-interface swing event-dispatch-thread

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

我的挥杆知识是有限的和生锈的,但我记得读到需要小心保持事件派发线程(EDT)上的GUI东西.

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

我应该实际使用swing.utils.invokeAndWait方法,例如在下面的示例代码中?


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

Run Code Online (Sandbox Code Playgroud)

现在,上面没有做任何事情来在invokeAndWait完成后从消息对话框以外的其他内容中创建值.

据推测,groovy'闭包'实现Runnable将使代码比上面更简单.

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

小智 8

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

如果对话框是模态的并且尚未显示,则在通过调用hide或dispose隐藏对话框之前,此调用将不会返回.这是允许的,显示来自事件调度线程的模式对话框,因为该工具包会确保另一个事件泵,同时其调用此方法的一个被阻止运行.

因此,JOptionPane尽管它阻塞,但在EDT 上运行是完全安全的.显然,show()从EDT 调用Dialog的方法是安全的,但事实并非如此,JOptionPane因为它的方法是创建GUI组件,添加监听器,在模态时访问其他容器并阻止对它们的输入等.你不希望所有这些完成了EDT,因为它不是线程安全的,可能会有问题.不可否认,我在使用JOptionPaneEDT 时从未见过任何问题,因此机会似乎很低,但它们肯定是可能的.为对话框的容器传入null并且只给出不可变对象(比如Strings)作为字段的参数将显着减少(甚至可能消除据我所知)发生错误的可能性,因为所有相关的GUI组件都是并且在它们不可见时在同一个线程中访问.但是,你应该安全并把它放在EDT上.打电话并不困难SwingUtilities.invokeAndWait().


Mat*_*ogt 5

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

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


Chr*_*sch 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");
}
Run Code Online (Sandbox Code Playgroud)