5

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

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

该事件在预期时被触发,但随后发生了一件奇怪的事情。当这个类的具体扩展有代码JDialogonClose()方法中创建一个新的,并且 thisJDialogdefaultCloseOperationis 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)调用一次,即使我不是故意调用它。

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

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

有没有人有任何想法?

谢谢!

4

2 回答 2

7

根据Java Dialog 教程

每个对话框都依赖于一个 Frame 组件。当该 Frame 被销毁时,其依赖的 Dialogs 也会被销毁。

当您使用不带任何参数的 JDialog 构造函数时,它

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

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

当您关闭对话框时,将调用SharedOwnerFrame'swindowClosed方法,该方法检查它拥有的所有窗口(此时是原始 SSCCE 对话框和新窗口),它发现没有一个是可见的,因此它自行处理。这会影响处理它拥有的所有对话框,这些对话框会向每个对话框发布一个窗口关闭事件。这会调用windowClosed您的侦听器,打开一个新对话框。我们又走了一遍:-)。关于您最后的评论,您每次都会获得额外的日志行,因为您SharedOwnerFrame拥有的每个对话都会获得一个。

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

 public void onClose() {
     JDialog dialog = new JDialog(this);
     dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
     dialog.setVisible(true);
 }
于 2012-04-20T00:05:33.317 回答
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);

    }

}
于 2012-04-19T21:42:21.357 回答