`WindowListener`表演,永久射击

wch*_*gin 5 java swing jdialog windowlistener

我有一个扩展的抽象类的应用程序JDialog.该类作为abstract void onClose(),并且在类的构造函数中添加了以下代码:

addWindowListener(new WindowAdapter() {
    @Override
    public void windowClosed(WindowEvent e) {
        onClose();
    }
}
Run Code Online (Sandbox Code Playgroud)

事件在预期时被触发,但随后发生了一件奇怪的事情.当这个类的一个具体的延长有代码来创建一个新JDialogonClose()方法,这JDialogdefaultCloseOperationJDialog.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);
    }

}
Run Code Online (Sandbox Code Playgroud)

单击"单击我"按钮后,空白JDialog出现并SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()显示在控制台窗口中.当我关闭空白对话框时,它再次出现,文本再次出现.

另一个非常有趣的事情是当我更改初始化行时

JDialog dialog = new JDialog();
Run Code Online (Sandbox Code Playgroud)

JDialog dialog = new JDialog() {
        @Override
        public synchronized void addWindowListener(WindowListener l) {
            super.addWindowListener(l);
            System.out
                    .println("SSCCE.onClose().new JDialog() {...}.addWindowListener()");
        }
    };
Run Code Online (Sandbox Code Playgroud)

我在控制台中获得以下输出:

单击"单击我"按钮时:

SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
Run Code Online (Sandbox Code Playgroud)

在第一次关闭对话框时:

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()
Run Code Online (Sandbox Code Playgroud)

在第二次关闭对话框时:

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()
Run Code Online (Sandbox Code Playgroud)

每次关闭对话框时,都会addWindowListener(WindowListener l)被称为额外的时间,即使我没有故意调用它.

我真的不希望在对话框中注册任何 WindowListener s,但我认为简单地覆盖addWindowListener(...)方法而不是调用super.addWindowListener(...)会太过于草率.

我在Mac OS X 10.6.8上运行Java 1.6.0_31,使用Eclipse Indigo(如果重要的话,使用WindowBuilder).

有没有人有任何想法?

谢谢!

Ian*_*nes 7

根据Java Dialog教程,

每个对话框都依赖于Frame组件.当该帧被销毁时,其依赖对话框也被销毁.

当你使用没有任何参数JDialog构造函数时,它

创建一个没有标题且没有指定Frame所有者的无模式对话框.共享的隐藏框架将被设置为对话框的所有者.

共享隐藏的帧是SwingUtilities$SharedOwnerFrame,并且在初始化时它将a注册WindowListener到所有拥有的窗口.

当您关闭对话框时,SharedOwnerFramewindowClosed方法被调用,这对于它拥有的所有窗口检查(在这一点上是原来SSCCE对话框和新的),发现没有一个是可见的,所以其配置本身.这会影响它所拥有的所有对话框,它会向每个对话框发布一个窗口关闭事件.这会调用windowClosed您的侦听器,打开一个新对话框.我们再去一轮:-).关于您的上一次评论,每次都会获得额外的日志行,因为每个对话框都SharedOwnerFrame拥有一个.

如果您使SSCCE对话框拥有新对话框(通过传递this给它的构造函数),那么您最终没有共享所有权,它可以正常工作:

 public void onClose() {
     JDialog dialog = new JDialog(this);
     dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
     dialog.setVisible(true);
 }
Run Code Online (Sandbox Code Playgroud)