// This is supposed to show a modal dialog and then hide it again. In practice,
// this works about 75% of the time, and the other 25% of the time, the dialog
// stays visible.
// This is on Ubuntu 10.10, running:
// OpenJDK Runtime Environment (IcedTea6 1.9) (6b20-1.9-0ubuntu1)
// This always prints
// setVisible(true) about to happen
// setVisible(false) about to happen
// setVisible(false) has just happened
// even when the dialog stays visible.
package modalproblemdemo;
import java.awt.Frame;
import javax.swing.JDialog;
import javax.swing.SwingUtilities;
public class Main {
public static void main(String[] args) {
final Dialogs d = new Dialogs();
new Thread() {
@Override
public void run() {
d.show();
d.hide();
}
}.start();
}
static class Dialogs {
final JDialog dialog;
public Dialogs() {
dialog = new JDialog((Frame) null, "Hello World", /*modal*/ true);
dialog.setSize(400, 200);
}
public void show() {
SwingUtilities.invokeLater(new Runnable() { public void run() {
dialog.setLocationRelativeTo(null);
System.out.println("setVisible(true) about to happen");
dialog.setVisible(true);
}});
}
public void hide() {
SwingUtilities.invokeLater(new Runnable() { public void run() {
System.out.println("setVisible(false) about to happen");
dialog.setVisible(false);
System.out.println("setVisible(false) has just happened");
}});
}
}
}
这显然是某种竞争条件。我认为这不像埃里克·罗伯逊的答案那么简单。对话框的show()
代码相当复杂,它包含一些从事件调度线程调用的特殊逻辑,并且还将事件发布到事件队列。也许事件发布的顺序在某种程度上受到线程延迟的影响。
也许你需要的是SwingUtilities.invokeAndWait()
,这样你就可以保证setVisible(true)
在您调用之前已完成执行setVisible(false)
. 正如 Skip Head 指出的,invokeAndWait 将阻塞,直到对话框关闭。
为什么你还需要它?
编辑:这是我所发生的情况:
- 你调用 d.show() 来发布
setVisible(true)
event
- 线程被调度程序置于睡眠状态,EDT 启动并开始执行第一个事件
- EDT 在第一个任务完成之前被踢出并发布显示对话框的实际事件
- 您的线程执行 d.hide() 来发布 setVisible(false) 事件。线程已结束,EDT 开始
- EDT完成第一个任务,将其显示事件放入事件队列
- 它转到下一个事件,瞧,这是 setVisible(false) 事件!
- 它弄乱了对话框的整个状态,并且它保持可见且无响应。
编辑2:看起来像进度监视器 http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/ProgressMonitor.html具有您正在尝试实现的功能。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)