`WindowListener`表演,永久射击

时间:2012-04-19 21:26:35

标签: java swing jdialog windowlistener

我有一个带有扩展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)。

有没有人有任何想法?

谢谢!

2 个答案:

答案 0 :(得分:7)

根据Java Dialog tutorial

  

每个对话框都依赖于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);

    }

}