What Is the Right Action to Take Upon Closing Windows in Java/Swing

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 Actions 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



Leave a reply



Submit