为什么在调用setVisible(false)和dispose()时会调用Window / Component Listeners?

时间:2016-01-12 12:25:49

标签: java swing jframe jdialog componentlistener

我看到的差异是(在JDK 1.7上运行):

  

setVisible(false),调用componentHidden windowClosed(API仅在dispose()上声明,所以即使它让我感到烦恼也没关系)< / p>

  

dispose(),调用windowClosed,但 componentHidden

短期运行的示例代码(MCVE):

public class JDialogTest extends JDialog {
    private static final long serialVersionUID = 1L;

    public JDialogTest(JFrame owner){
        super(owner,ModalityType.APPLICATION_MODAL);
        init();
    }
    private void init() {
        this.getContentPane().setLayout(new GridLayout(1,2));
        JButton btnVisible = new JButton("Set visible false");
        btnVisible.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JDialogTest.this.setVisible(false);
            }
        });
        JButton btnDispose = new JButton("Dispose");
        btnDispose.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JDialogTest.this.dispose();
            }
        });
        this.getContentPane().add(btnVisible);
        this.getContentPane().add(btnDispose);
        this.pack();
    }

    public static void main(String[] args) {

        //A fake frame to test JDialog
        JFrame fakeFrame = new JFrame("Fake Frame");
        fakeFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fakeFrame.getContentPane().setLayout(new BorderLayout());
        JButton btnOpen = new JButton("Open Dialog");
        fakeFrame.getContentPane().add(btnOpen,BorderLayout.CENTER);
        fakeFrame.pack();
        fakeFrame.setLocationRelativeTo(null);

        //Generate the test dialog
        final JDialogTest dialog = new JDialogTest(fakeFrame);
        dialog.addComponentListener(new ComponentAdapter() {

            @Override
            public void componentShown(ComponentEvent e) {
                System.out.println("Component Shown");
            }
            @Override
            public void componentHidden(ComponentEvent e) {
                System.out.println("Component Hidden");
            }
        });

        dialog.addWindowListener(new WindowAdapter() {
            @Override
            public void windowOpened(WindowEvent e) {
                System.out.println("Window open");
            }
            @Override
            public void windowClosed(WindowEvent e) {
                System.out.println("Window closed");
            }
        });
        dialog.setLocationRelativeTo(null);

        btnOpen.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dialog.setVisible(true);
            }
        });
        fakeFrame.setVisible(true);
    }
}

注意:该示例包含JDialog,但我在JFrame中看到相同的行为,以测试将侦听器简单地附加到fakeFrame,并添加类似的按钮。 (在MVCE中避免使其 M inimal))。

我考虑过这篇文章:

JDialog setVisible(false) vs dispose()

  • 在答案中似乎应该没有区别,请使用dispose() ...

API文档:

Window.setVisible(boolean b)Window.dispose()ComponentListener.componentHidden(ComponentEvent e)WindowListener.windowClosed(WindowEvent e)

我为什么要关心:出于好奇,当然还因为我使用按钮关闭窗口(调用dispose()),界面也可以通过顶部/右边关闭窗口关闭图标和 alt + F4 (调用setVisible(false) !?)。因此,不能使用上述监听器中的任何一个。只有HierarchyListener才会捕获它们,这似乎是反直觉的。

编辑:这个问题的范围是“为什么会这样”?目的是什么?“。我期待dispose()同时调用它们!我在API文档中找不到任何线索,为什么不这样做。

2 个答案:

答案 0 :(得分:4)

  

界面也可以靠近/右窗口关闭图标 alt + F4 (调用setVisible(false)!)

这由默认关闭操作决定。您可以使用setDefaultCloseOperation进行设置。默认值为HIDE_ON_CLOSE,这就是您获得componentHidden调用的原因。如果您将其设置为DISPOSE_ON_CLOSE,那么您将获得windowClosed调用。设置为后者将允许您仅注册这些事件类型。

无论如何,隐藏和处理会做不同的事情。处置时释放隐藏的资源不会。此外,隐藏最后一个窗口将不会退出JVM,而处理它将。

事件调度的技术方面,有很多错综复杂的问题。在处理窗口的同时调用其隐藏方法时,事件的调度在操作完成后完成。这意味着EDT可以“事后”调度事件。由于窗口关闭,它不会调度隐藏事件。

答案 1 :(得分:1)

我在为所描述的行为苦苦挣扎时遇到了这个问题。虽然 componentHidden 已被 ComponentEvent(COMPONENT_HIDDEN) 安排到对话框的事件队列,但我的 setVisible(false) 处理程序没有被调用。

我的对话框是模态的,调用者在对话框关闭并从 dispose 返回后显式调用 setVisible(true)。这可能是对话框事件队列和应用程序事件队列之间的“竞争条件”。因此,我的工作是站在来电者这边:

SwingUtilities.invokeLater(myDialog::dispose);

这应该推迟对话的处理,直到其事件队列耗尽; componentHidden 在此设置中被调用。