Java for OS X 2013-004如何影响(中断)Swing应用程序?
似乎Java for OS X 2013-004(Java 1.6.0_51)打破了一些Swing应用程序: https : //discussions.apple.com/message/22279872?tstart = 0#22279872?tstart = 0 http:// www。 mathworks.com/matlabcentral/answers/79489
我的应用加载,但它没有正常重绘。 点击按钮和其他操作实际上似乎有效,但是如果调整框架大小,显示只会更新 – 真的很奇怪。
有谁知道问题可能是什么?
编辑:似乎Apple修复了它: http : //lists.apple.com/archives/java-dev/2013/Jun/msg00055.html
Apple发布了这些更新的修订版本已解决此问题: http : //support.apple.com/kb/DL1572 (10.7,10.8 +) http://support.apple.com/kb/DL1573 (10.6-只要)
更新2013-06-21:这个答案包含一些可能有用的解决方法和替代方案,但@ sidney-markowitz-biomatters的答案包含正确的代码修复 – 需要从事件线程设置LAF!
最近的问题似乎与破坏Aqua Look and Feel(LAF)的更新有关,这是Mac OS X上Swing应用程序的默认设置。
如果您需要Aqua LAF,那么没有太多选择。 您可能需要等待Apple的下一次Java更新(我假设他们会优先解决这个问题,因为它是他们自己的LAF)。 您也可以尝试使用Java Application Bundler (即捆绑Oracle JRE并避免使用系统的JRE)。
如果您可以使用不同的LAF,那么您的应用应该正常工作。 它至少为PaperCut做了(003更新引起了一些窗口焦点问题,004更新引起了混乱)。
一些选择:
-
使用Java代码中的Java 版本特定的跨平台LAF(例如Nimbus或Metal):
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName())
-
从Java代码设置特定的LAF:
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel")
-
覆盖终端的默认LAF:
java -Dswing.defaultlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel MyApp
在我们的例子中,我们在代码中显式调用了UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
,并且想要一个不涉及代码更改的解决方法(即修补程序),因此我们需要覆盖默认系统 LAF,如下所示。
-
从终端覆盖系统LAF:
java -Dswing.systemlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel ...
-
从
Info.plist
文件覆盖系统LAF (如果已捆绑为Mac应用程序,也适用于其他VM选项)(例如,在My.app/Contents/Info.plist
)。您希望将
-Dswing.systemlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel
添加到VMOptions
的
值的VMOptions
。 选项是空间分隔的,就像从终端一样。 例如,如果您已有useScreenMenuBar
选项:VMOptions -Dcom.apple.macos.useScreenMenuBar=true -Dswing.systemlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel
编辑:@trashgod要求提供可重复的示例。 我不确定004更新的全部问题是什么,但这是一个简单的再现:
更新2013-06-21 – 错误的方式,重现错误:
public class AquaLafTest { public static void main(String[] args) throws Exception { javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); javax.swing.JOptionPane.showMessageDialog(null, "msg"); } }
-
使用004更新附带的Apple JRE运行(例如,在
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
)。 观察到消息不可见,对话框图标不可见,按钮不可见。 -
使用较旧的Apple JRE或其他JRE运行。 观察对话框按预期显示。
更新2013-06-21 – 正确的方式,在事件线程上,正常工作:
public class AquaLafTest { public static void main(String[] args) throws Exception { javax.swing.SwingUtilities.invokeAndWait(new Runnable() { public void run() { try { javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); javax.swing.JOptionPane.showMessageDialog(null, "msg"); } catch (Exception e) { e.printStackTrace(); } } }); } }
您曾经能够从Swing线程外部调用UIManager.setLookAndFeel()
。 通过设置该调用的外观来启动应用程序可能很常见。 Swing API文档说,你可以从该线程外部调用的唯一Swing方法是在方法的JavaDoc中标记为线程安全的方法。 setLookAndFeel
未标记为thread-safe
。 由于它不涉及在调用时显示任何内容并且它一直在工作,我敢打赌,许多人认为它是在实际执行任何GUI之前设置一些配置设置的方法,并且只需调用一次并忘记关于它。
尝试将调用包装到UIManager.setLookAndFeel
,就像使用所有其他Swing方法一样,以确保它在Swing线程中运行(有时称为调度或UI线程)。 还要查看在Swing线程外部调用的其他Swing方法,以防此更新使其他方法在线程安全方面更加挑剔。
[添加示例代码]
@ tom-clift在他的回答中添加了显示代码失败和正常工作代码的优秀示例。 我正在更新此答案,以包含他的示例片段,以显示您应该用setLookAndFeel替换您的调用。 对UIManager方法的任何其他调用执行相同操作,例如,如果您在其中设置特定属性。
javax.swing.SwingUtilities.invokeAndWait(new Runnable() { public void run() { try { javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { e.printStackTrace(); } } });