java - `WindowListener` 装模作样,永久开火

标签 java swing jdialog windowlistener

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

addWindowListener(new WindowAdapter() {
    @Override
    public void windowClosed(WindowEvent e) {
        onClose();
    }
}

事件按预期触发,但随后发生了一件奇怪的事情。当这个类的具体扩展在onClose() 方法中有创建一个新的JDialog 的代码时,这个JDialog defaultCloseOperationJDialog.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);
    }

}

单击“单击我”按钮后,将出现空白的 JDialogSSCCE.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

当您关闭对话框时,将调用 SharedOwnerFramewindowClosed 方法,检查它拥有的所有窗口(此时是原始 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/

相关文章:

java - 希望 JDialog 为 "modal"但不阻止其他窗口

java - 通过代码处理 JDialog,不要让用户关闭它

java - 创建 Kafka Producer 并调用方法 send()、flush() 和 close() 的正确顺序是什么?

java - recyclerview-selection 如何监听 onSelectionEnter 事件和 onSelectionExit 事件

Java 模运算符

java - 如何正确处理图形上下文——我需要最后尝试吗? (Java 1.7)

java - Java Swing 的错误消息

swing - GridPanel 是如何确定大小的?

java - JDialog的方法返回null

java - TicTacToe GUI 应用程序重置按钮