有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java调用setVisible(false)和dispose()时,为什么窗口/组件侦听器的调用方式不同?

我看到的区别是(在JDK1.7上运行):

setVisible(false), invokes componentHidden but not windowClosed (The API states only on dispose() so it's OK even if it irritates me)

但是

dispose(), invokes windowClosed but not 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最小)

我考虑过这个职位:

JDialog setVisible(false) vs dispose()

  • 在回答似乎是应该没有区别,使用dispose()

API文档:

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

我为什么要关心:自然是出于好奇,但也因为我使用按钮关闭窗口(调用^{),界面也可以通过上/右窗口关闭图标和alt+F4(调用^{)关闭。因此,不能使用上述侦听器中的任何一个。只有HierarchyListener会同时捕获它们,这似乎违反直觉

编辑:问题的范围是“为什么会这样”?目的何在?“。我希望dispose()同时调用这两个!我在API文档中找不到任何线索来解释为什么不调用


共 (2) 个答案

  1. # 1 楼答案

    我是在与所描述的行为作斗争时遇到这个问题的。虽然setVisible(false)已将ComponentEvent(COMPONENT_HIDDEN)调度到对话框的事件队列,但未调用我的componentHidden处理程序

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

    SwingUtilities.invokeLater(myDialog::dispose);
    

    这将推迟对话框的处理,直到其事件队列耗尽^在此设置中调用{}

  2. # 2 楼答案

    the interface can also be close by top/right window close icon alt+F4 (invoking setVisible(false)!?)

    这由默认的关闭操作确定。您可以使用setDefaultCloseOperation设置它。默认值为HIDE_ON_CLOSE,这就是为什么会得到componentHidden调用。如果将其设置为DISPOSE_ON_CLOSE,则将得到一个windowClosed调用。设置为后者将允许您仅注册这些事件类型

    不管怎样,隐藏和处置做不同的事情。释放释放隐藏时使用的资源不会。此外,隐藏最后一个窗口不会在释放时退出JVM

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