我有一个带有抽象类的应用程序,它扩展了 JDialog
。该类作为一个abstract void onClose()
,并且在该类的构造函数中,添加了以下代码:
addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
onClose();
}
}
事件按预期触发,但随后发生了一件奇怪的事情。当这个类的具体扩展在onClose()
方法中有创建一个新的JDialog
的代码时,这个JDialog
的 defaultCloseOperation
是 JDialog.DISPOSE_ON_CLOSE
,事件不断触发,直到我强制退出操作。
我已将代码隔离到以下 SSCCE:
// package removed
// imports removed
public class SSCCE extends JDialog {
public static void main(String[] args) {
SSCCE s = new SSCCE();
s.pack();
s.setVisible(true);
}
public SSCCE() {
setLayout(new GridLayout(1, 0, 0, 0));
JButton btn = new JButton("click me");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
dispose();
}
});
addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
System.out
.println("SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()");
onClose();
}
});
add(btn);
}
public void onClose() {
JDialog dialog = new JDialog();
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
}
}
单击“单击我”按钮后,将出现空白的 JDialog
和 SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()
出现在控制台窗口中。当我关闭空白对话框时,它再次出现并且文本再次出现。
另一个非常有趣的事情是当我改变初始化行时
JDialog dialog = new JDialog();
到
JDialog dialog = new JDialog() {
@Override
public synchronized void addWindowListener(WindowListener l) {
super.addWindowListener(l);
System.out
.println("SSCCE.onClose().new JDialog() {...}.addWindowListener()");
}
};
我在控制台中得到以下输出:
当点击“点击我”按钮时:
SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
在第一次关闭对话框时:
SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
在第二次关闭对话框时:
SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
每次我关闭对话框时,addWindowListener(WindowListener l)
都会被调用一次附加,尽管我并不是有意调用它。
我真的不想在对话框中注册 任何 WindowListener
,但我认为只需覆盖 addWindowListener(...)
方法而不调用 super.addWindowListener(...)
太草率了。
我在 Mac OS X 10.6.8 上运行 Java 1.6.0_31,使用 Eclipse Indigo(如果需要的话,使用 WindowBuilder)。
有没有人有什么想法?
谢谢!
最佳答案
根据 Java Dialog tutorial ,
Every dialog is dependent on a Frame component. When that Frame is destroyed, so are its dependent Dialogs.
当您使用 JDialog constructor without any arguments , 它
Creates a modeless dialog without a title and without a specified Frame owner. A shared, hidden frame will be set as the owner of the dialog.
那个共享的隐藏框架是 SwingUtilities$SharedOwnerFrame
,在初始化时它向所有拥有的窗口注册一个 WindowListener
。
当您关闭对话框时,将调用 SharedOwnerFrame
的 windowClosed
方法,检查它拥有的所有窗口(此时是原始 SSCCE 对话框和新的),它发现没有一个是可见的,所以它自行处理。这具有处理它拥有的所有对话框的影响,它向每个对话框发送一个窗口关闭事件。这会在您的监听器中调用 windowClosed
,打开一个新对话框。然后我们再来一次:-)。关于你最后的评论,你每次都会得到额外的日志行,因为你在 SharedOwnerFrame
拥有的每个对话框中得到一个。
如果您让 SSCCE 对话框拥有新对话框(通过将 this
传递到它的构造函数中),那么您不会以共享所有权结束并且它工作正常:
public void onClose() {
JDialog dialog = new JDialog(this);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
}
关于java - `WindowListener` 装模作样,永久开火,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10237047/