`WindowListener`起作用,永久触发 [英] `WindowListener` acting up, perpetual firing

查看:120
本文介绍了`WindowListener`起作用,永久触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

}

单击单击我"按钮后,将显示空白的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)都被称为额外的时间,即使我不是故意将其称为.<​​/p>

我真的不希望在对话框中注册任何 WindowListener,但是我认为仅重写addWindowListener(...)方法而不调用super.addWindowListener(...)会太草率.

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

有人有什么想法吗?

谢谢!

解决方案

按照没有任何参数的JDialog构造函数,它

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

该共享的隐藏帧为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);
 }

I have an application with an abstract class that extends JDialog. The class as an abstract void onClose(), and, in the class's constructor, the following code is added:

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

The event is fired when expected, but then a strange thing happens. When a concrete extension of this class has code to create a new JDialog in the onClose() method, and this JDialog's defaultCloseOperation is JDialog.DISPOSE_ON_CLOSE, the event is fired continuously, until I force quit the operation.

I have isolated the code to the following 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);
    }

}

Upon clicking the "click me" button, the blank JDialog appears and SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed() appears in the console window. When I close the blank dialog, it reappears again and the text appears again.

Another really interesting thing is that when I change the initialization line from

JDialog dialog = new JDialog();

to

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

I get the following output in the console:

When clicking the "click me" button:

SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()

At the first closing of the dialog:

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()

At the second closing of the dialog:

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()

Each time I close the dialog, addWindowListener(WindowListener l) is called an additional time, even though it I am not intentionally calling it.

I don't really want any WindowListeners to be registered on the dialog, but I think that simply overriding the addWindowListener(...) method and not calling super.addWindowListener(...) would be too sloppy.

I'm running Java 1.6.0_31 on Mac OS X 10.6.8, using Eclipse Indigo (with WindowBuilder, if it matters).

Does anyone have any ideas?

Thanks!

解决方案

As per the Java Dialog tutorial,

Every dialog is dependent on a Frame component. When that Frame is destroyed, so are its dependent Dialogs.

When you use the JDialog constructor without any arguments, it

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.

That shared hidden frame is SwingUtilities$SharedOwnerFrame, and on initialization it registers a WindowListener to all owned windows.

When you close your dialog, the SharedOwnerFrame's windowClosed method is called, which checks for all windows it owns (at this point is the original SSCCE dialog and the new one), it finds none are visible, and so it disposes itself. This has the impact of disposing all of the dialogs it owns, which posts a window close event to each. This calls windowClosed in your listener, opening a new dialog. And round we go again :-). Regarding your last comments, you get additional log lines each time because you get one per dialog the SharedOwnerFrame owns.

If you make the SSCCE dialog own the new dialog (by passing this into its constructor) then you don't end up with shared ownership and it works fine:

 public void onClose() {
     JDialog dialog = new JDialog(this);
     dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
     dialog.setVisible(true);
 }

这篇关于`WindowListener`起作用,永久触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆