Java 窗户关闭会多次起火。这是一个bug还是一个特性?

Java 窗户关闭会多次起火。这是一个bug还是一个特性?,java,swing,dispose,Java,Swing,Dispose,以下面的代码为例: import java.awt.Dialog; import java.awt.event.ActionEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JDialog; import javax.swin

以下面的代码为例:

import java.awt.Dialog;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

public class WeirdDialogShitTest implements Runnable {
    private JFrame frame;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new WeirdDialogShitTest());
    }

    @Override
    public void run() {
        frame = new JFrame("Test");
        frame.add(new JButton(new AbstractAction("Show Dialog") {
            @Override
            public void actionPerformed(ActionEvent event) {
                showDialog();
            }
        }));
        frame.pack();
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.setVisible(true);
    }

    private void showDialog() {
        JDialog dialog = new JDialog(frame, "Dialog", Dialog.ModalityType.DOCUMENT_MODAL);
        dialog.add(new JLabel("Content here"));
        dialog.pack();
        dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        dialog.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent event) {
                JOptionPane.showMessageDialog(frame, "windowClosed fired");
            }
        });
        dialog.setVisible(true);
    }
}
我希望在对话框关闭时调用一次
windowClosed

实际发生的是,它被调用两次——一次是在对话框关闭时,一次是在包含框架关闭时

当我追踪它看发生了什么时,我发现:

  • 在父级上调用
    dispose()
    时,它也会处理所有子级。很公平

  • 尽管不再存在,所有子对话框仍保留在子对话框列表中。这在我看来似乎是不可靠的。(它们曾经被移除过吗?)
  • dispose()
    无条件激发
    windowClosed
    无论窗口是否已被释放。对我来说,这似乎也是不可靠的
最终结果是对话框本身和每个祖先分别关闭一次
windowClosed
:/


但这可能是预期的行为?

应该使用
frame.setDefaultCloseOperation(WindowConstants.EXIT\u ON\u CLOSE)在主框架上。这会解决你的问题。尝试:

public class WeirdDialogShitTest implements Runnable {
    private JFrame frame;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new WeirdDialogShitTest());
    }

    @Override
    public void run() {
        frame = new JFrame("Test");
        frame.add(new JButton(new AbstractAction("Show Dialog") {
            @Override
            public void actionPerformed(ActionEvent event) {
                showDialog();
            }
        }));
        frame.pack();

        frame.setVisible(true);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //Use EXIT_ON_CLOSE here.
    }

    private void showDialog() {
        JDialog dialog = new JDialog(frame, "Dialog", Dialog.ModalityType.DOCUMENT_MODAL);
        dialog.add(new JLabel("Content here"));
        dialog.pack();
        dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        dialog.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent event) {
                JOptionPane.showMessageDialog(frame, "windowClosed fired");

            }
        });
        dialog.setVisible(true);
    }
}

“尽管不再存在,但所有子对话框仍保留在子对话框列表中。在我看来,这似乎是不可靠的。(它们是否被删除过?)。dispose的目的是释放窗口及其子组件正在使用的本机资源。这些组件仍然存在于java中,可以自由引用,没有任何例外。根据
dispose()
文档,它们可以恢复到与
pack()
show()
@vandale相同的状态。我意识到这一点,但我希望在重新验证之前将其从子帧列表中删除。如果我创建了1000个对话框并处理了所有对话框,那么在应用程序退出之前,是否所有1000个对话框都保留在内存中(我们有多个主窗口,所以在关闭时退出甚至不是一个选项。