Swing on OSX: Como Trapar o Comando-Q?

Depois de ser convencido (“escolarizado”) que os aplicativos do Swing no Mac parecem nativos , estou tentando fazer com que os meus pareçam o mais nativo possível. Tudo parece ótimo, mas quando eu windowStateChanged(WindowEvent e) comando + Q ou faço isso no menu, o meu windowStateChanged(WindowEvent e) não está triggersndo no meu JFrame principal (se eu sair de qualquer outra forma, ele triggers). Como posso responder ao verdadeiro Apple sair?

    A resposta mais votada é excelente, mas apenas para preencher o “melhor caminho”:

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

    Isso acionará o evento de retorno de chamada de fechamento de janela padrão que deve funcionar muito bem para o código portátil.

    Como resultado da discussão abaixo parece que é crucial para fazer isso realmente no início do aplicativo. Eu escrevi isso no início do inicializador estático da class principal antes de qualquer código de interface do usuário ser executado.

    Você pode implementar com.apple.eawt.ApplicationListener e responder ao evento Quit . Um exemplo pode ser encontrado no exemplo da Biblioteca de referência do Mac OS X , OSXAdapter .

    Adendo: Consulte Java para Mac OS X 10.6 Atualização 3 e 10.5 Atualização 8 Notas sobre o Release para obter informações sobre descontinuidade, a class com.apple.eawt.Application reformulada e o local da documentação da API para as extensões Apple Java. Clique com a tecla Control pressionada ou clique com o botão direito do mouse no arquivo .jdk para Show Package Contents . Você pode navegar pelas classs de com.apple.eawt entre as origens do OpenJDK.

    Como mostrado neste exemplo completo, você pode especificar o QuitStrategy desejado; um WindowListener responderá a ⌘Q :

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

    Conforme observado aqui , você pode definir a propriedade na linha de comando

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

    ou no início do programa, antes de postar quaisquer events da GUI:

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

    imagem

    Console, depois 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 é uma boa pergunta, e devo admitir que não tenho a resposta. No entanto, alguns anos atrás, quando eu estava trabalhando em um aplicativo Java e enfrentei esse problema, resolvi isso registrando um gancho de encerramento com o tempo de execução que faria o que eu queria que o aplicativo fizesse antes de sair. É uma solução pesada, mas funcionou. Você pode dar uma olhada no meu código e ver se isso ajuda.

    Eu estava vendo originalmente uma violação de ‘restrição de access’ ao tentar acessar as subclasss com.apple.eawt.Application e com.apple.eawt. *.

    (Nota: estou programando em um MAC, usando o Eclipse, com o Java 1.6 usando Swing)

    Então, eu precisava modificar o meu caminho de compilation do java para permitir o access às subclasss do Apple adicionando a regra de access “com / apple / eawt / **”. Depois disso, este código abaixo foi capaz de compilar e trabalhar para mim:

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

    Você já tentou configurar o comandoQ como um acelerador no seu menu? Você pode fazer seu aplicativo responder a ele?

    Não tenho certeza, mas acho que isso funciona no Linux e provavelmente no Windows com o equivalente AltF4 . Meu aplicativo responde ao pressionamento de tecla “kill”, eu processo algum código de limpeza e, em seguida, faço um System.exit() programático.

    Se você está “apenas” após o manuseio de saída, você também pode querer pegar o WindowEvent WINDOW_CLOSING , onde tradicionalmente “tem certeza?” coisas são feitas.

    Olhando para o link para o Java para Mac OS X 10.6 Atualização 3 e 10.5 Atualização 8 Notas da Versão Notei que há uma seção sobre Ação de Saída Padrão . Isso descreve uma propriedade do sistema para solicitar que todas as janelas sejam fechadas em resposta ao item de menu “Sair”, que parece exatamente o que é necessário? Eu usei isso no meu próprio aplicativo (usando Info.plist para definir a propriedade no OS X somente), e parece funcionar como descrito. Isso presumivelmente funcionaria apenas em versões recentes do Java / OS X, mas para essas plataformas parece uma solução simples e não requer nenhuma alteração de código.