Swing on OSX: How to Trap command-Q?
Solution 1:
You can implement com.apple.eawt.ApplicationListener
and respond to the Quit
event. An example may be found in the Mac OS X Reference Library example, OSXAdapter.
Addendum: See Java for Mac OS X 10.6 Update 3 and 10.5 Update 8 Release Notes for information on deprecation, the redesigned com.apple.eawt.Application
class, and the location of API documentation for the Apple Java extensions. Control-click or right-click on the .jdk
file to Show Package Contents
. You can browse the classes of com.apple.eawt
among the OpenJDK sources.
As shown in this complete example, you can specify the desired
QuitStrategy
; a WindowListener
will respond to ⌘Q:
Application.getApplication().setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
As noted here, you can set the property from the command line
java -Dapple.eawt.quitStrategy=CLOSE_ALL_WINDOWS -cp build/classes gui.QuitStrategyTest
or early in the program, before posting any GUI events:
System.setProperty("apple.eawt.quitStrategy", "CLOSE_ALL_WINDOWS");
EventQueue.invokeLater(new QuitStrategyTest()::display);
Console, after ⌘Q:
java.vendor: Oracle Corporation
java.version: 1.8.0_60
os.name: Mac OS X
os.version: 10.11
apple.eawt.quitStrategy: CLOSE_ALL_WINDOWS
java.awt.event.WindowEvent[WINDOW_CLOSING,opposite=null,oldState=0,newState=0] on frame0
Code:
package gui;
import java.awt.EventQueue;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JTextArea;
/**
* @see https://stackoverflow.com/a/7457102/230513
*/
public class QuitStrategyTest {
private void display() {
JFrame f = new JFrame("QuitStrategyTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.out.println(e);
}
});
f.add(new JTextArea(getInfo()));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private String getInfo() {
String[] props = {
"java.vendor",
"java.version",
"os.name",
"os.version",
"apple.eawt.quitStrategy"
};
StringBuilder sb = new StringBuilder();
for (String prop : props) {
sb.append(prop);
sb.append(": ");
sb.append(System.getProperty(prop));
sb.append(System.getProperty("line.separator"));
}
System.out.print(sb);
return sb.toString();
}
public static void main(String[] args) {
System.setProperty("apple.eawt.quitStrategy", "CLOSE_ALL_WINDOWS");
EventQueue.invokeLater(new QuitStrategyTest()::display);
}
}
Solution 2:
The top voted answer is excellent but just to fill in the "best way":
System.setProperty("apple.eawt.quitStrategy", "CLOSE_ALL_WINDOWS");
This will trigger the standard window closing callback event which should work really nicely for portable code.
As a result of the discussion below it seems that its crucial to do this really early in the app. I wrote this early in the static initializer of the main class before any UI code was executed.
Solution 3:
This is a pretty good question, and I must admit I don't have the answer. However, a couple years ago when I was working on a Java app and faced this problem, I solved it by registering a shutdown hook with the runtime that would do what I wanted the app to do before quitting. It's a heavy-handed solution but it worked. You can take a look at my code and see if it helps.