What is the right action to take upon closing windows in java/swing?
You can use the setDefaultCloseOperation()
method of JDialog
, specifying DISPOSE_ON_CLOSE
:
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
See also 12.8 Program Exit.
Addendum: Incorporating @camickr's helpful answer, this example exits when either the window is closed or the close button is pressed.
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
/** @see http://stackoverflow.com/questions/5540354 */
public class DialogClose extends JDialog {
public DialogClose() {
this.setLayout(new GridLayout(0, 1));
this.add(new JLabel("Dialog close test.", JLabel.CENTER));
this.add(new JButton(new AbstractAction("Close") {
@Override
public void actionPerformed(ActionEvent e) {
DialogClose.this.setVisible(false);
DialogClose.this.dispatchEvent(new WindowEvent(
DialogClose.this, WindowEvent.WINDOW_CLOSING));
}
}));
}
private void display() {
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new DialogClose().display();
}
});
}
}
How to close a Java Swing application from the code
Your JFrame default close action can be set to "DISPOSE_ON_CLOSE
" instead of EXIT_ON_CLOSE
(why people keep using EXIT_ON_CLOSE is beyond me).
If you have any undisposed windows or non-daemon threads, your application will not terminate. This should be considered a error (and solving it with System.exit is a very bad idea).
The most common culprits are java.util.Timer and a custom Thread you've created. Both should be set to daemon or must be explicitly killed.
If you want to check for all active frames, you can use Frame.getFrames()
. If all Windows/Frames are disposed of, then use a debugger to check for any non-daemon threads that are still running.
How to programmatically close a JFrame
If you want the GUI to behave as if you clicked the X
close button then you need to dispatch a window closing event to the Window
. The ExitAction
from Closing An Application allows you to add this functionality to a menu item or any component that uses Action
s easily.
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
Java Swing adding Action Listener for EXIT_ON_CLOSE
Try this.
addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent e)
{
System.out.println("Closed");
e.getWindow().dispose();
}
});
How to capture a JFrame's close button click event?
import javax.swing.JOptionPane;
import javax.swing.JFrame;
/*Some piece of code*/
frame.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
if (JOptionPane.showConfirmDialog(frame,
"Are you sure you want to close this window?", "Close Window?",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION){
System.exit(0);
}
}
});
If you also want to prevent the window from closing unless the user chooses 'Yes', you can add:
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
JFrame Exit on close Java
You need the line
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Because the default behaviour for the JFrame when you press the X button is the equivalent to
frame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
So almost all the times you'll need to add that line manually when creating your JFrame
I am currently referring to constants in WindowConstants
like WindowConstants.EXIT_ON_CLOSE
instead of the same constants declared directly in JFrame
as the prior reflect better the intent.
Performing action when closing JFrame
You can pass a MainFrame handle to the DetailFrame constructor. Then, on clicking the Save button, the DetailFrame would call a function in MainFrame and pass the changes to it.
Another way is to create a public boolean
variable in DetailFrame and set it to true
when the Save button is clicked. This way MainFrame will know whether the DetailFrame was closed or Save'd.
EDIT: Some more ideas:
Use JDialog
instead of JFrame
. JDialog.setVisible
is modal, i.e. it will block the calling function until the dialog is closed; this way you can process the results of the dialog in the same "Details" button listener.
To access the dialog after it is called, store the dialog in a separate variable. First construct the dialog, then show it, and then process the result by analyzing its variables.
Store the results of editing in other public variables of DetailFrame
(or let's call it DetailDialog
). This should happen only when the "Save" button is clicked. This may even allow to go without the boolean variable (depends on the types of values you are editing).
DetailDialog dlg = new DetailDialog();
dlg.setVisible(true);
if(dlg.approvedResult != null) {
// process the result...
}
EDIT: Sorry, JDialog
is not modal by default. Need to call a special super
constructor to make it modal.
Also, here you will have to pass the reference to MainFrame
to the dialog constructor, but you still can declare it as a simple JFrame
and avoid unnecessary dependencies.
To get the reference to the enclosing MainFrame
from within the anonymous ActionListener, use MainFrame.this
.
To be able to change the button text after it was created, you will have to store the button in a member variable.
Main Frame...
public class MainFrame extends JFrame
{
private JButton details = new JButton("Add Detail");
public MainFrame()
{
super("Main Frame");
getContentPane().add(details);
details.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
DetailDialog dlg = new DetailDialog(MainFrame.this);
dlg.setVisible(true);
if(dlg.approved){
details.setText("Edit Detail");
}
}
});
}
}
Detail Dialog... (not Frame)
public class DetailDialog extends JDialog
{
public boolean approved = false;
public DetailDialog(JFrame parent)
{
super(parent,"Detail Dialog",true); // modal dialog parented to the calling frame
JButton save = new JButton("Save");
getContentPane().add(save);
save.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
// Save whatever content
approved = true;
dispose();
}
});
}
}
In Java, where to put code to reliably fire on window close?
After finding a number of similar questions here:
- WindowAdapter windowClosed method not running
- Workaround for non-compliant JVM not sending WindowClosing events
- Message when closing JFrame Window
I created an app that fired System.out.println()
statements on each of windowDeactivated
, windowClosing
and WindowClosed
events and tried closing both a JFrame
and a JDialog
window with the system X button and with a button that just setVisible(false)
:
/**
* Test program to explore the relationship between defaultCloseOperation
* states, and the sequence of events triggered when closing a window
* with the (X) button vs using setVisible(false).
*
* @author MaskedCoder
*
*/
package testwindowadapter;
import java.awt.EventQueue;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.WindowConstants;
/**
* Class to listen for window close events
*/
public class WindowNotifier extends WindowAdapter implements WindowListener
{
public WindowNotifier() {
super();
}
@Override
public void windowClosing(WindowEvent e)
{
super.windowClosing(e);
System.out.println(e.getComponent().getClass().getSimpleName() + ".windowClosing fired");
}
@Override
public void windowClosed(WindowEvent e) {
super.windowClosed(e); //To change body of generated methods, choose Tools | Templates.
System.out.println(e.getComponent().getClass().getSimpleName() + ".windowClosed fired");
}
@Override
public void windowDeactivated(WindowEvent e) {
super.windowDeactivated(e);
System.out.println(e.getComponent().getClass().getSimpleName() + ".windowDeactivated fired");
}
}
/**
* Creates new form TestDialog
*/
public class TestDialog extends javax.swing.JDialog {
public TestDialog(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
addWindowListener(new WindowNotifier());
cboDefaultCloseOp.setSelectedIndex(getDefaultCloseOperation());
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
btnClose = new javax.swing.JButton();
cboDefaultCloseOp = new javax.swing.JComboBox();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("WindowAdapter Test");
btnClose.setText("Close window");
btnClose.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCloseActionPerformed(evt);
}
});
cboDefaultCloseOp.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "DO_NOTHING_ON_CLOSE", "HIDE_ON_CLOSE", "DISPOSE_ON_CLOSE" }));
cboDefaultCloseOp.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboDefaultCloseOpItemStateChanged(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(cboDefaultCloseOp, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGap(58, 58, 58)
.addComponent(btnClose)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(cboDefaultCloseOp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(btnClose)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {
setVisible(false);
}
private void cboDefaultCloseOpItemStateChanged(java.awt.event.ItemEvent evt) {
setDefaultCloseOperation(cboDefaultCloseOp.getSelectedIndex());
}
// Variables declaration - do not modify
private javax.swing.JButton btnClose;
private javax.swing.JComboBox cboDefaultCloseOp;
// End of variables declaration
}
/**
* Creates new form TestFrame
*/
public class TestFrame extends javax.swing.JFrame {
public TestFrame() {
super();
initComponents();
addWindowListener(new WindowNotifier());
cboDefaultCloseOp.setSelectedIndex(getDefaultCloseOperation());
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
cboDefaultCloseOp = new javax.swing.JComboBox();
btnClose = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
cboDefaultCloseOp.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "DO_NOTHING_ON_CLOSE", "HIDE_ON_CLOSE", "DISPOSE_ON_CLOSE", "EXIT_ON_CLOSE" }));
cboDefaultCloseOp.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboDefaultCloseOpItemStateChanged(evt);
}
});
btnClose.setText("Close window");
btnClose.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCloseActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(cboDefaultCloseOp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGap(41, 41, 41)
.addComponent(btnClose)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(cboDefaultCloseOp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(btnClose)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {
setVisible(false);
}
private void cboDefaultCloseOpItemStateChanged(java.awt.event.ItemEvent evt) {
setDefaultCloseOperation(cboDefaultCloseOp.getSelectedIndex());
}
// Variables declaration - do not modify
private javax.swing.JButton btnClose;
private javax.swing.JComboBox cboDefaultCloseOp;
// End of variables declaration
}
public class TestWindowAdapter {
public TestWindowAdapter() {
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// TestDialog MainWin = new TestDialog(null, true);
TestFrame MainWin = new TestFrame();
MainWin.setVisible(true);
}
});
}
}
From that, I created a WindowListener that reliably fired once and only once, optionally asking for permission before allowing closure. It works for JFrame and JDialog. I chose to define "closed" as any time that the window goes from visible to not visible and "opened" as any time that the window goes from not visible to visible. This will not include iconification / deiconification. windowClosing
duties will not be performed if the confirmClose
denies permission to close thus preventing the window from becoming invisible.
/**
*
* @author MaskedCoder
*/
package testwindowadapter;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
public class ReliableOneShotCloseListener extends WindowAdapter implements WindowListener {
public interface CloseDuties {
public boolean confirmClose(WindowEvent e);
public void windowClosing(WindowEvent e);
}
private CloseDuties closeDuties;
private int defaultCloseOperation;
private boolean windowClosingFired = false;
public ReliableOneShotCloseListener(int iniDefaultCloseOperation, CloseDuties iniCloseDuties) {
super();
closeDuties = iniCloseDuties;
defaultCloseOperation = iniDefaultCloseOperation;
}
private int getDefaultCloseOperation(WindowEvent e) {
if(e.getComponent() instanceof JFrame) {
return ((JFrame) e.getComponent()).getDefaultCloseOperation();
}
else if(e.getComponent() instanceof JDialog) {
return ((JDialog) e.getComponent()).getDefaultCloseOperation();
}
else throw new IllegalArgumentException("WindowEvent.getComponent() is " + e.getComponent().getClass().getSimpleName() + ", must be JFrame or JDialog.");
}
private void setDefaultCloseOperation(WindowEvent e, int newDefaultCloseOperation) {
if(e.getComponent() instanceof JFrame) {
((JFrame) e.getComponent()).setDefaultCloseOperation(newDefaultCloseOperation);
}
else if(e.getComponent() instanceof JDialog) {
((JDialog) e.getComponent()).setDefaultCloseOperation(newDefaultCloseOperation);
}
else throw new IllegalArgumentException("WindowEvent.getComponent() is " + e.getComponent().getClass().getSimpleName() + ", must be JFrame or JDialog.");
}
private void performCloseDuties(WindowEvent e) {
if(!windowClosingFired) {
if(closeDuties.confirmClose(e)) {
setDefaultCloseOperation(e, defaultCloseOperation);
closeDuties.windowClosing(e);
windowClosingFired = true;
}
else
setDefaultCloseOperation(e, WindowConstants.DO_NOTHING_ON_CLOSE);
}
}
public int getDefaultCloseOperation() {
return defaultCloseOperation;
}
public void setDefaultCloseOperation(int newDefaultCloseOperation) {
defaultCloseOperation = newDefaultCloseOperation;
}
@Override
public void windowOpened(WindowEvent e) {
windowClosingFired = false;
}
@Override
public void windowClosing(WindowEvent e) {
performCloseDuties(e);
}
@Override
public void windowClosed(WindowEvent e) {
performCloseDuties(e);
}
@Override
public void windowActivated(WindowEvent e) {
windowClosingFired = false;
}
@Override
public void windowDeactivated(WindowEvent e) {
if(!e.getComponent().isVisible())
performCloseDuties(e);
}
}
Adding this as a windowlistener to a JDialog or JFrame extension and implementing a version of CloseDuties adds a great deal of flexibility and reliability to the business of closing a window.
Do something before window closes after user presses [x]
take a look of this may its helps you. Closing an Application
You can give your own implementation if some one press close button.
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener( new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
// Here you can give your own implementation according to you.
}
});
Window closing in Swing Application Framework
The WindowEvent class has a method call getWindow(), which returns the window that is closing.
Inside your windowClosing
method you can check: if the window is the main application window, use the code that you currently have. If it is not, just call Window.dispose()
Edit: I didn't notice that you were creating custom dialogs in your application. Maybe you forget to dispose them? You should add code like the one in the auto generated about box:
@Action public void closeAboutBox() {
dispose();
}
and call this action whenever the dialog closes. If this is not the problem, a thread dump will probably help you in order to find out which thread is running when you close the main window.
Related Topics
How to Create a Class Literal of a Known Type: Class<List<String>>
Split Regex to Extract Strings of Contiguous Characters
How to Update an Entity Using Spring-Data-Jpa
Change a Method at Runtime via a Hot Swap Mechanism
Integer Arithmetic in Java with Char and Integer Literal
Checking for a Null Int Value from a Java Resultset
Java - How to Receive Point Coordinates After Mouse Button Release (Jfreechart)
Using Java to Decrypt Openssl Aes-256-Cbc Using Provided Key and Iv
How to Copy Java Collections List
Time Complexity of Java's Substring()
Why Static Fields Are Not Initialized in Time
Spark Strutured Streaming Automatically Converts Timestamp to Local Time
Arraylist or List Declaration in Java
Hibernate: Flush() and Commit()