我有一个简单的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);
}
现在,上面没有做任何事情来在invokeAndWait完成后从消息对话框以外的其他内容中创建值。
据推测,groovy'闭包'实现Runnable将使代码比上面更简单。
是否需要invokeAndWait?如果是这样,有人请举例说明正确的实现,以便使用groovy得到类似confirmDialog的结果吗?
答案 0 :(得分:8)
对JOptionPane
的showXXXDialog()之一的调用是BLOCKING,直到用户选择ok / cancel / etc.通常,您不会在事件调度线程(EDT)上放置这种缓慢阻塞的指令,因为每个其他GUI组件都会冻结。所以,直觉不要把它放在EDT上是好的,但这也是错误的。原因如其他一些人所述,该方法创建GUI组件,这应始终在EDT上完成。但阻止怎么样?您会注意到,即使您在EDT上运行它,它也能正常工作。原因在源代码中找到。 JOptionPane
类创建一个Dialog对象,然后调用show()
后跟dispose()
,其中第一个是阻塞线程。如果您阅读了评论(或javadoc),您会看到它说明了这个方法:
如果对话框是模态的并且尚未显示,则此调用不会 返回,直到通过调用hide或dispose隐藏对话框。它是 允许从事件调度线程显示模态对话框 因为工具包将确保另一个事件泵运行时 调用此方法的一个被阻止。
因此,尽管它被阻止,但在EDT上运行JOptionPane
是完全安全的。显然,从EDT调用Dialog的show()
方法是安全的,但JOptionPane
的情况也是如此,因为它的方法是创建GUI组件,添加监听器,在模态时访问其他容器并阻止对它们的输入您不希望所有这些都在EDT之外完成,因为它不是线程安全的并且可能存在问题。不可否认,我在EDT使用JOptionPane
时从未见过任何问题,所以机会似乎很低,但它们肯定是可能的。为对话框的容器传入null并且只给出不可变对象(比如String
s)作为字段的参数将显着减少(甚至可能消除据我所知)发生错误的可能性,因为所有相关的GUI组件在不可见的同一个线程内制作和访问。但是,你应该安全并把它放在EDT上。拨打SwingUtilities.invokeAndWait()
并不困难。
答案 1 :(得分: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
答案 2 :(得分: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");
}