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"); } } 
  1. 使用004更新附带的Apple JRE运行(例如,在/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home )。 观察到消息不可见,对话框图标不可见,按钮不可见。

  2. 使用较旧的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(); } } });