父类的非终止窗口监听器

时间:2014-06-10 03:35:08

标签: java swing jframe dispose windowlistener

任何人都可以解释为什么以下程序在关闭子窗口时不会终止吗?

我创建了一个简单的应用程序,其中父JFrame实例化了一个JDialog的子类。当我将父引用传递给子类以便可以使用父类创建JDialog时(即:new JDialog(parent);),从父类添加到它的窗口侦听器会导致程序一旦子窗口关闭,永远不会终止。窗口确实关闭(在可见性方面),但程序本身仍然运行。父项的默认关闭操作设置为JFrame.EXIT_ON_CLOSE。子项的默认关闭操作设置为JDialog.DISPOSE_ON_CLOSE

如果我没有向子类传递父引用,以便在没有父窗口的情况下实例化JDialog,则示例会在子窗口关闭时终止。例如,如果使用以下内容,程序将终止:ChildWindow prompt = new ChildWindow(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)

1 个答案:

答案 0 :(得分:3)

使用Windows 7和Java 8测试并且没有问题,当我尝试使用Java 7或Java 6时,它只是继续打印Window Closed. ...

因此,我使用windowClosed

的测试更新了frame.isVisible方法
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();
                }
            }
        });
    }
});

让它发挥作用......现在看看我能否找到原因......

我“想”这发生了什么......

  1. okButton被触发,dialog.dispose被称为
  2. dialog.dispose正在设置第一个windowClosed活动
  3. WindowListener已收到windowClosed事件的通知,该事件处理框架......
  4. 框架试图关闭它的子窗口,导致对话框通知WindowListener他们正在关闭等等......转到3并重复...
  5. 这是一个错误,似乎在Java 8中得到修复...因为结束事件已经被推送到事件队列,所以你不会得到StackOverflowException ...

    在这种情况下,另一种选择是从触发WindowListener事件的Window中删除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) {
                    e.getWindow().removeWindowListener(this);
                    frame.dispose();
                }
            });
        }
    });