Reputation: 3656
Can anyone explain why the following program does not terminate when closing the child window?
I have created a simple application with a parent JFrame
that instantiates a child class with a JDialog
. When I pass the parent reference into the child class so that the JDialog
can be created with a parent (ie: new JDialog(parent);
), the window listener that is added to it from the parent class causes the program to never terminate once the child window has been closed. The windows do indeed close (in terms of visibility), but the program itself still runs. The default close operation for the parent is set to JFrame.EXIT_ON_CLOSE
. The default close operation for the child is set to JDialog.DISPOSE_ON_CLOSE
.
If I pass no parent reference to the child class so that the JDialog
is instantiated without a parent window, the example does terminate when the child window is closed. For instance, the program terminates if the following is used: ChildWindow prompt = new ChildWindow(null);
Parent Class:
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();
}
}
});
}
}
Child Class:
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;
}
}
Output:
Window closed.
Window closed.
Window closed.
... (does not terminate)
Upvotes: 1
Views: 748
Reputation: 347314
Tested using Windows 7 and Java 8 and had not issues, when I tried Java 7 or Java 6, it simply kept on printing out Window Closed.
...
So, I updated the windowClosed
method using a test for 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();
}
}
});
}
});
And got it to work...now to see if I can find out why...
I "think" what's happening is this...
okButton
is triggered, dialog.dispose
is calleddialog.dispose
is setting up the first windowClosed
eventWindowListener
is been notified of the windowClosed
event, which is disposing of the frame...WindowListener
AGAIN that they are closing and so forth...goto 3 and repeat...This is a bug, which appears to be fixed in Java 8...Because the closing events are been pushed onto the Event Queue, you won't get a StackOverflowException
...
In this case, another option would be to remove the WindowListener
from the Window
that triggered the windowClosed
event...
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();
}
});
}
});
Upvotes: 3