Java 来自父类的非终止窗口侦听器

Java 来自父类的非终止窗口侦听器,java,swing,jframe,dispose,windowlistener,Java,Swing,Jframe,Dispose,Windowlistener,有人能解释为什么在关闭子窗口时下列程序没有终止吗 我创建了一个简单的应用程序,其中包含一个父类JFrame,它用JDialog实例化了一个子类。当我将父引用传递到子类中,以便可以使用父类创建JDialog(即:newjdialog(parent);)时,从父类添加到它的窗口侦听器会导致程序在子窗口关闭后永不终止。窗口确实关闭了(就可见性而言),但程序本身仍在运行。父对象的默认关闭操作设置为JFrame。在关闭时退出。子项的默认关闭操作设置为JDialog.DISPOSE\u ON\u close

有人能解释为什么在关闭子窗口时下列程序没有终止吗

我创建了一个简单的应用程序,其中包含一个父类
JFrame
,它用
JDialog
实例化了一个子类。当我将父引用传递到子类中,以便可以使用父类创建
JDialog
(即:
newjdialog(parent);
)时,从父类添加到它的窗口侦听器会导致程序在子窗口关闭后永不终止。窗口确实关闭了(就可见性而言),但程序本身仍在运行。父对象的默认关闭操作设置为
JFrame。在关闭时退出。子项的默认关闭操作设置为
JDialog.DISPOSE\u ON\u close

如果我没有向子类传递父引用,因此在没有父窗口的情况下实例化
JDialog
,则当关闭子窗口时,该示例将终止。例如,如果使用以下命令,程序将终止:
ChildWindow prompt=newchildwindow(null)

父类:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ParentWindow {
    private JFrame frame;
    private JPanel contentPane = new JPanel(new BorderLayout(0, 0));
    private JButton btnNewButton = new JButton("Open Child Window!");

    public ParentWindow() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(contentPane);

        btnNewButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                ChildWindow prompt = new ChildWindow(frame); // or use null for no parent

                prompt.getDialog().addWindowListener(new WindowAdapter() {
                    @Override
                    public void windowClosed(WindowEvent e){
                        // .. get some information from the child before disposing 
                        System.out.println("Window closed."); // does not terminate when passing frame as parent
                        frame.dispose();
                    }
                });
            }
        });

        contentPane.add(btnNewButton);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    new ParentWindow();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
儿童班:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ChildWindow {
    private JDialog dialog;
    private JButton okButton = new JButton("Close");

    public ChildWindow(Window parent) {
        dialog = new JDialog(parent);
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);

        dialog.getContentPane().setLayout(new BorderLayout());
        dialog.getContentPane().add(okButton, BorderLayout.CENTER);
        okButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dialog.dispose();
            }
        });

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

    public JDialog getDialog() {
        return dialog;
    }

}
输出:

Window closed.
Window closed.
Window closed.
... (does not terminate)

使用Windows7和Java8进行测试,没有问题,当我尝试Java7或Java6时,它只是继续打印出关闭的
窗口。

因此,我使用对
frame.isVisible的测试更新了
windowClosed
方法

btnNewButton.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        ChildWindow prompt = new ChildWindow(frame); // or use null for no parent

        prompt.getDialog().addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
                // .. get some information from the child before disposing 
                System.out.println("Window closed."); // does not terminate when passing frame as parent
                if (frame.isVisible()) {
                    frame.dispose();
                }
            }
        });
    }
});
让它工作…现在看看我是否能找到原因

我“认为”发生的事情是

  • ok按钮
    被触发,调用
    对话框。dispose
  • dialog.dispose
    正在设置第一个
    windowClosed
    事件
  • WindowListener
    已收到
    windowClosed
    事件的通知,该事件正在处理帧
  • 框架试图关闭其子窗口,这导致对话框再次通知
    WindowListener他们正在关闭,以此类推…转到3并重复
  • 这是一个bug,在Java 8中似乎已修复…因为关闭事件被推送到事件队列中,所以不会得到
    StackOverflowException

    在这种情况下,另一个选项是从触发
    windowClosed
    事件的
    窗口中删除
    WindowListener

    btnNewButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            ChildWindow prompt = new ChildWindow(frame); // or use null for no parent
    
            prompt.getDialog().addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosed(WindowEvent e) {
                    e.getWindow().removeWindowListener(this);
                    frame.dispose();
                }
            });
        }
    });
    

    对我来说很好…@MadProgrammer你试过关闭子窗口吗?是的,打开了3,关闭了第一个…等了一两秒钟,JVM终止了…@MadProgrammer当我运行它时,当父窗口关闭时,程序肯定会终止,但如果我关闭任何子窗口,它就会卡住,不会终止(使用子窗口的关闭按钮或
    JButton
    close按钮).What OS,What Java version?在这里也可以使用,除了在我的环境中使用JDK1.7u60时,它会打印两次。使用JDK1.8u5时,它会按预期工作,并且只打印一次。有趣的发现,谢谢。由于它是一个创建的无模式对话框,有没有更好的方法(从其他类外部)获取信息当对话框关闭时,问题是最后一个转折点(JVM)@CanadianDavid将是