问题
我们的独立Swing应用程序在某些特定事件(按钮单击等)上显示模态JDialog.该对话框包含一些其他Swing组件(JLabel,JButtons,...).而不是通过JDialog.setBounds(...)我们调用的方法JDialog.pack()(或者方法隐式调用它)显式设置其维度.通过方法计算的维数总是不变的(例如300x100像素.)不幸的是,有时可见对话框的实际维度是1x1 px().JOptionPaneshowDialog(...)pack()JDialog.getSize().equals(new Dimension(1, 1))
JDialog初始化
我们JDialog在应用程序中初始化s 有两种方法.我们检查了两个初始化方法总是从EventDispatchThread调用.
第一种方法
我们只创建一个ADialog其子类的实例JDialog.这是我们的初始化过程的片段:
ADialog dialog = new ADialog();
dialog.setContentPane(content);
dialog.setVisible(true);
Run Code Online (Sandbox Code Playgroud)
这是我们的ADialog实施:
public class ADialog extends JDialog implements ComponentListener {
public JfosDialog(Frame owner) {
super(owner);
init();
}
private void init() {
super.addComponentListener(this);
}
@Override
public void componentShown(ComponentEvent e) {
// Calling pack() at this place is really weird, but we
// have to do it since some subclasses put their
// content to dialog in overriden componentShown().
pack();
}
@Override
public void componentMoved(ComponentEvent e) { /** not interested */ }
@Override
public void componentResized(ComponentEvent e) { /** not interested */ }
}
Run Code Online (Sandbox Code Playgroud)
第二种方法
public JOptionPane showDialog(...) {
JOptionPane jop = new JOptionPane(message, msgType, option, null, textMessages);
JDialog dialog = jop.createDialog(owner, titleMsg);
setDialogTraversal(dialog);
dialog.setVisible(true);
dialog.dispose();
return jop;
}
Run Code Online (Sandbox Code Playgroud)
再生性
环境
使用第一个初始化方法重现问题
我们只显示然后隐藏对话N次(0 <N <1000)并且一次对话的维度是1x1(线程问题的标志,竞争条件).由于这个问题的本质是非常随机的,我们编写了简单的java.awt.Robot脚本,它在循环中显示和隐藏对话框.它比手动操作更舒服.
使用第二个初始化方法重现问题
步骤与第一种方法相同:只显示然后隐藏对话框N次.不幸的是,我们无法在我们的开发环境中重现它,但它可以很容易地在生产PC中重现(与我们的开发环境中有不同的CPU,安装了一些永久创建系统负载的防病毒软件等)
到目前为止,我们无法在某种测试/样本项目中重现该问题.这可能表明我们的应用程序存在问题.但是,似乎问题可能出现在Swing的本机代码中(请参阅跟踪部分).
追踪
我们在64位OpenJDK 1.6.0_24中追踪了我们问题的原因.我们发现,维度JDialog被修改XConfigureEvent了XToolkit.事件是在XToolkit.run(boolean)从本机方法调用返回之后的方法的事件循环中构造的.
为简化起见,我在这里只发布了一个代码片段,说明XToolkit了我们跟踪结果的事件循环机制.您可能还会在此处看到完整的源代码.
public class XToolkit ... {
...
public void run(boolean loop) {
XEvent ev = new XEvent();
while(true) {
awtLock();
try {
if (loop == SECONDARY_LOOP) {
...
} else {
...
// ===========================================
// The following invocation of native method sometimes
// updates ev object in a way that ev.get_type() method returns value 22
// indicating that the event's type is XConfigureEvent.
// In such case, as I mentioned in text above, the value of
// ev.get_xconfigure().get_width() / .get_height()
// is sometimes 1.
XlibWrapper.XNextEvent(getDisplay(),ev.pData); // <-----
// ===========================================
}
...
// The XConfigureEvent with get_width() == 1 and
// get_heigth() == 1 is dispatcher here:
dispatchEvent(ev); // <-----
...
} catch (...) {
...
}
}
}
...
}
Run Code Online (Sandbox Code Playgroud)
你有任何想法如何解决这个错误/更深入地追踪它/更健壮地再现它......?
我很欣赏任何想法,因为这个bug真的很痛苦.
pack()应该尊重组件的首选(或最小尺寸,具体取决于layou tmanager).
尝试明确设置对话框中组件的最小和首选大小,看看是否能解决问题.
就竞争条件而言,它也可能是代码中的错误初始化.当布局管理器查询其首选(或最小大小)时,大多数组件将遵循其内容(例如,JLabel的文本).因此,填充组件的代码可能并不总是以相同的顺序运行.您是否确保在AWT线程上创建对话框和所有包含的组件?
| 归档时间: |
|
| 查看次数: |
257 次 |
| 最近记录: |