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

Pet*_*erg 6 java swing jframe jdialog componentlistener

我看到的区别是(在JDK 1.7上运行):

setVisible(false),调用componentHidden 调用windowClosed(API仅表示dispose()如此,即使它激怒了我也没关系)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:该示例具有a 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文档中的任何线索.

use*_*551 4

界面也可以通过顶部/右侧窗口关闭图标alt+关闭F4(调用 setVisible(false)!?)

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

无论如何,隐藏和处置会产生不同的效果。处理会释放所使用的资源,而隐藏则不会。此外,隐藏最后一个窗口不会退出 JVM,而处理它则会退出。

至于事件调度的技术方面,有很多复杂的地方。虽然处理窗口确实会调用其隐藏方法,但事件的调度是在操作完成后完成的。这意味着 EDT 可以“事后”调度事件。由于窗口已关闭,因此它不会调度隐藏事件。