JOptionPane.showMessageDialog 和 swing.utils.invokeAndWait 的(事件调度)线程安全用法是什么?
我有一个简单的常规脚本,它的主执行线程需要向用户显示一些对话框。
我的挥杆知识有限且生疏,但我记得读过关于需要小心地将 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“闭包”实现 Runnable 的事实将使代码比上面更简单。
是否需要调用AndWait?如果是这样,有人可以给出一个正确实现的例子,以获得像使用groovy的confirmDialog这样的结果吗?
I have a simple groovy script that from its main thread of execution needs to display some dialog boxes to the user.
My swing knowledge is limited and rusty but I recall reading about the need to be careful to keep GUI stuff on the event-dispatching thread (EDT).
If I just call the static JOptionPane.showMessageDialog
method from my main thread am I right in assuming this would violate the correct practice of keeping GUI stuff on the EDT?
Should I actually be using the swing.utils.invokeAndWait method such as in the following example code?
void showHelloThereDialog()
throws Exception {
Runnable showModalDialog = new
Runnable() {
public void run() {
JOptionPane.showMessageDialog(
myMainFrame, "Hello There");
}
};
SwingUtilities.invokeAndWait
(showModalDialog);
}
Now the above doesn't do anything to make values from something other than a message dialog available after invokeAndWait completes.
Presumably the fact that groovy 'closures' implement Runnable will make for simpler code than above.
Is invokeAndWait required? And if so would someone please give an example of correct implementation to get the result of something like a confirmDialog using groovy?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对 JOptionPane 的 showXXXDialog() 之一的调用将被阻塞,直到用户选择“确定”/“取消”等。一般来说,您通常不会将如此缓慢的阻塞指令放在事件调度线程 (EDT) 上,因为每个其他 GUI 组件都会冻结。因此,不把它放在 EDT 上的直觉是好的,但也是错误的。原因如其他一些人所述,该方法创建 GUI 组件,并且这应该始终在 EDT 上完成。但是阻塞又如何呢?您会注意到,即使您在 EDT 上运行它,它也能正常工作。原因在源码中找到。
JOptionPane
类创建一个 Dialog 对象,然后调用show()
,然后调用dispose()
,其中第一个调用会阻塞线程。如果您阅读注释(或 javadoc),您将看到它是关于该方法的:因此,尽管 JOptionPane 会阻塞,但在 EDT 上运行 JOptionPane 是完全安全的。显然,在 EDT 之外调用 Dialog 的
show()
方法是安全的,但对于JOptionPane
则不然,因为它的方法是创建 GUI 组件、添加侦听器、访问其他组件您不希望所有这些都在 EDT 之外完成,因为它不是线程安全的,并且可能会出现问题。诚然,我在 EDT 之外使用JOptionPane
时从未遇到过问题,因此可能性似乎很低,但它们肯定是有可能的。为对话框的容器传递 null 并仅将不可变对象(例如 String )作为字段的参数将显着减少(据我所知甚至可能消除)出现不良情况的可能性发生这种情况是因为所有相关的 GUI 组件都是在同一个线程中创建和访问的,而它们是不可见的。但是,为了安全起见,您应该将其放在 EDT 上。调用SwingUtilities.invokeAndWait()
并不困难。A call to one of
JOptionPane
's showXXXDialog() is BLOCKING until the user selects ok/cancel/etc. In general you do not put such slow blocking insturctions on the Event Dispatch Thread (EDT) as a rule because every single other GUI component will freeze. So, a gut instinct to not put it on the EDT is good, but it is also wrong. The reason is as stated by some others, the method creates GUI components and this should always be done on the EDT. But what about the blocking? You will notice that even if you do run it on the EDT, it works fine. The reason is found inside the source code. TheJOptionPane
class creates a Dialog object and then callsshow()
followed bydispose()
, the first of which is what blocks the thread. If you read the comments (or javadoc), you will see that it says this about the method:So, it is perfectly safe to run
JOptionPane
on the EDT despite it blocking. Obviously, it is safe to call Dialog'sshow()
method off the EDT but the same is not true forJOptionPane
because its methods are creating GUI components, adding listeners, accessing other containers when modal and blocking input to them, etc. You do not want all of this done off the EDT because it is not thread-safe and there could be problems. Admittedly, I have never seen problems when usingJOptionPane
off the EDT and so the chances seem low, but they are most certainly possible. Passing in a null for the container of the dialog and only giving immutable objects (likeString
s) as arguments to the fields will significantly reduce (maybe even eliminate as far as I know) the chance of something bad happening because all relevant GUI components are made and accessed within the same thread while they are not visible. But, you should just be safe and put it on the EDT. It is not that difficult to callSwingUtilities.invokeAndWait()
.这应该在 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
This should be on the EDT so invokeAndWait, or invokeLater, are required. You can tell since the code for JOptionPane.showMessageDialog eventually creates and modifies Swing components. As of Java 6, Sun says that all manipulations of Swing components (whether they have been realized or not) must be done on the 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
看一下groovy.swing.SwingBuilder,它封装了invokeAndWait和invokeLater。你的例子可以写成:
Take a look at groovy.swing.SwingBuilder, it encapsulates invokeAndWait and invokeLater. Your example can be written as: