Swing en OSX: cómo atrapar el comando-Q?

Después de convencerme (“educado”) de que las aplicaciones Swing en Mac se ven como nativas , estoy tratando de que las mías parezcan lo más nativas posible. Todo se ve muy bien, pero cuando windowStateChanged(WindowEvent e) comando + Q o lo hago desde el menú, mi windowStateChanged(WindowEvent e) no se windowStateChanged(WindowEvent e) en mi JFrame principal (si salgo de otra manera, se dispara). ¿Cómo puedo responder al verdadero abandono de Apple?

La respuesta más votado es excelente, pero solo para completar la “mejor manera”:

 System.setProperty("apple.eawt.quitStrategy", "CLOSE_ALL_WINDOWS"); 

Esto desencadenará el evento de callback de cierre de ventana estándar que debería funcionar muy bien para el código portátil.

Como resultado de la discusión a continuación, parece que es crucial hacer esto muy temprano en la aplicación. Escribí esto temprano en el inicializador estático de la clase principal antes de que se ejecutara cualquier código de UI.

Puede implementar com.apple.eawt.ApplicationListener y responder al evento Quit . Se puede encontrar un ejemplo en el ejemplo de la biblioteca de referencia de Mac OS X , OSXAdapter .

Anexo: Consulte Java para Mac OS X 10.6 Update 3 y 10.5 Update 8 Release Notes para obtener información sobre deprecation, la clase com.apple.eawt.Application rediseñada y la ubicación de la documentación API para las extensiones Apple Java. .jdk la .jdk Control o haga clic con el botón derecho en el archivo .jdk para Show Package Contents . Puede navegar por las clases de com.apple.eawt entre las fonts OpenJDK.

Como se muestra en este ejemplo completo, puede especificar la QuitStrategy deseada; un WindowListener responderá a ⌘Q :

 Application.getApplication().setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS); 

Como se observa aquí , puede establecer la propiedad desde la línea de comando

 java -Dapple.eawt.quitStrategy=CLOSE_ALL_WINDOWS -cp build/classes gui.QuitStrategyTest 

o al principio del progtwig, antes de publicar cualquier evento GUI:

 System.setProperty("apple.eawt.quitStrategy", "CLOSE_ALL_WINDOWS"); EventQueue.invokeLater(new QuitStrategyTest()::display); 

imagen

Consola, después de ⌘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 

Código:

 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); } } 

Esta es una muy buena pregunta, y debo admitir que no tengo la respuesta. Sin embargo, hace un par de años, cuando estaba trabajando en una aplicación Java y me enfrenté a este problema, lo resolví registrando un enlace de cierre con el tiempo de ejecución que haría lo que quería que la aplicación hiciera antes de abandonar. Es una solución pesada pero funcionó. Puede echar un vistazo a mi código y ver si ayuda.

Al principio estaba viendo una violación de ‘restricción de acceso’ al intentar acceder a las subclases com.apple.eawt.Application y com.apple.eawt. *.

(Nota: estoy progtwigndo en un MAC, usando Eclipse, con Java 1.6 usando Swing)

Así que tuve que modificar mi ruta de comstackción java para permitir el acceso a las subclases de Apple agregando la regla de acceso “com / apple / eawt / **”. Después de que este código a continuación fue capaz de comstackr y trabajar para mí:

 //NOTE: This code only works for MAC OS. If you run this on Windows //the application never starts (so you literally need to remove this block of code) import com.apple.eawt.*; import com.apple.eawt.QuitHandler; Application a = Application.getApplication(); a.setQuitHandler(new QuitHandler() { @Override public void handleQuitRequestWith(com.apple.eawt.AppEvent.QuitEvent qe, com.apple.eawt.QuitResponse qr) { // TODO Auto-generated method stub int res = JOptionPane.showConfirmDialog(frame, "Are you sure you want to exit the program?", "Quit ?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (res == JOptionPane.YES_OPTION) qr.performQuit(); else qr.cancelQuit(); } }); 

¿Has intentado configurar el comandoQ como acelerador en tu menú? ¿Puedes hacer que tu aplicación responda?

No estoy seguro, pero creo que esto funciona en Linux y probablemente en Windows con el AltF4 equivalente. Mi aplicación responde a la pulsación de tecla “matar”, proceso un código de limpieza y luego hago un System.exit() programático.

Si estás “solo” después de un manejo elegante de la salida, es posible que también quieras ver el WindowEvent WINDOW_CLOSING , donde tradicionalmente “¿estás seguro?” cosas se hacen.

Mirando el enlace a Java para Mac OS X 10.6 Actualización 3 y 10.5 Notas de la versión de actualización 8 Observé que hay una sección en Acción de abandono predeterminado . Esto describe una propiedad del sistema para solicitar que todas las ventanas se cierren en respuesta al elemento de menú “Salir”, que parece ser exactamente lo que se necesita. Lo he usado en mi propia aplicación (usando Info.plist para establecer la propiedad solo en OS X), y parece funcionar como se describe. Supuestamente, esto solo funcionaría en versiones recientes de Java / OS X, pero para esas plataformas parece una solución ordenada y no requiere ningún cambio de código.