在OSX上摇摆:如何捕获命令-Q?

在确信(“受过教育”)Mac上的Swing应用看起来本机之后 ,我试图让我的外观尽可能本地化。 一切看起来都很棒,但是当我点击命令 + Q或从菜单中执行时,我的windowStateChanged(WindowEvent e)没有在我的主JFrame上触发(如果我以任何其他方式退出,它会触发)。 我如何回应真正的Apple退出?

最高投票的答案非常好,但只是填写“最佳方式”:

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

这将触发标准窗口关闭回调事件,该事件对于可移植代码应该非常好用。

由于下面的讨论,似乎在应用程序的早期做到这一点至关重要。 在执行任何UI代码之前,我在主类的静态初始化程序中尽早编写了这个。

您可以实现com.apple.eawt.ApplicationListener并响应Quit事件。 可以在Mac OS X参考库示例OSXAdapter中找到示例。

附录:有关弃用的信息,重新设计的com.apple.eawt.Application类以及Apple Java扩展的API文档的位置,请参阅Java for Mac OS X 10.6 Update 3和10.5 Update 8发行说明 。 按住Control键单击或右键单击.jdk文件以Show Package Contents 。 您可以在OpenJDK源中浏览com.apple.eawt的类。

如完整示例所示,您可以指定所需的QuitStrategy ; WindowListener将响应⌘Q

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

如此处所述,您可以从命令行设置属性

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

或者在程序的早期,在发布任何GUI事件之前:

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

图片

⌘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 

码:

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

这是一个非常好的问题,我必须承认我没有答案。 然而,几年前,当我在Java应用程序上工作并遇到这个问题时,我通过在运行时注册一个关闭钩子解决了这个问题,这个钩子会在退出之前完成我想让应用程序做的事情。 这是一个严厉的解决方案,但它的工作原理。 您可以查看我的代码 ,看看它是否有帮助。

在尝试访问com.apple.eawt.Application和com.apple.eawt。*子类时,我最初看到了“访问限制”违规。

(注意:我正在使用Eclipse编程MAC,使用Swing编写Java 1.6)

所以我需要通过添加“com / apple / eawt / **”访问规则来修改我的java构建路径以允许访问apple子类。 之后,下面的代码能够为我编译和工作:

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

您是否尝试过设置命令Q作为菜单中的加速器? 你能让你的应用回应吗?

我不是肯定的,但我认为这适用于Linux,可能还有Windows和等效的AltF4 。 我的应用程序响应“查杀”按键,我处理一些清理代码,然后我做一个程序化的System.exit()

如果您在正常退出处理之后“只是”,您可能还想要捕获WindowEvent WINDOW_CLOSING ,传统上“你确定吗?” 东西完成了。

查看Java for Mac OS X 10.6 Update 3和10.5 Update 8发行说明的链接,我注意到有一个关于Default Quit Action的部分。 这描述了一个系统属性,它要求所有窗口都关闭以响应“退出”菜单项,这听起来就像需要的那样? 我在我自己的应用程序中使用它(使用Info.plist仅在OS X上设置属性),它似乎按照描述工作。 这可能只适用于最近的Java / OS X版本,但对于这些平台来说似乎是一个简洁的解决方案,并且不需要任何代码更改。