我有一个带有扩展JDialog
的抽象类的应用程序。该类为abstract void onClose()
,并且在类的构造函数中添加了以下代码:
addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
onClose();
}
}
事件在预期时被触发,但随后发生了一件奇怪的事情。如果此类的具体扩展程序具有在JDialog
方法中创建新onClose()
的代码,并且此JDialog
的{{1}}为defaultCloseOperation
,则该事件被连续发射,直到我强行退出操作。
我已将代码隔离到以下SSCCE:
JDialog.DISPOSE_ON_CLOSE
点击“点击我”按钮后,系统会显示空白// 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
方法而不是调用{{1}太过邋。了。
我在Mac OS X 10.6.8上运行Java 1.6.0_31,使用Eclipse Indigo(如果重要的话,使用WindowBuilder)。
有没有人有任何想法?
谢谢!
答案 0 :(得分:7)
每个对话框都依赖于Frame组件。当该框架被销毁时,其依赖对话框也将被销毁。
使用JDialog constructor without any arguments时,
创建没有标题且没有指定Frame所有者的无模式对话框。共享的隐藏框架将被设置为对话框的所有者。
共享隐藏框架为SwingUtilities$SharedOwnerFrame
,初始化时会向所有拥有的窗口注册WindowListener
。
当您关闭对话框时,会调用SharedOwnerFrame
的{{1}}方法,该方法会检查它拥有的所有窗口(此时是原始的SSCCE对话框和新的对话框),它会找到没有一个是可见的,所以它处理自己。这会影响它所拥有的所有对话框,它会向每个对话框发布一个窗口关闭事件。这将在您的侦听器中调用windowClosed
,打开一个新对话框。我们再去一轮:-)。关于您的上一条评论,每次都会获得额外的日志行,因为windowClosed
拥有的每个对话框都有一条日志行。
如果您使SSCCE对话框拥有新对话框(通过将SharedOwnerFrame
传递到其构造函数中),那么您最终不会获得共享所有权并且工作正常:
this
答案 1 :(得分:4)
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
public class SSCCE extends JDialog {
public static void main(String[] args) {
SSCCE s = new SSCCE();
s.pack();
s.setVisible(true);
}
private WindowAdapter wa = new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
System.out
.println("SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()");
onClose();
}
};
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(
wa);
add(btn);
}
public void onClose() {
removeWindowListener(wa);
JDialog dialog = new JDialog();
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
}
}