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

我的应用程序加载,但它不能正常重绘。点击按钮和其他操作实际上似乎是有效的,但是只有当帧大小调整时显示才会更新-真的很奇怪。

有谁知道是什么问题吗?

编辑:似乎苹果修复了它:http://lists.apple.com/archives/java-dev/2013/Jun/msg00055.html

更新2013-06-21:此答案包含一些可能有用的变通方法和替代方案,但@sidney-markowitz-biomatters的答案包含正确的代码修复- LAF需要从事件线程设置!

最近的问题似乎与更新破坏了Aqua Look and Feel (LAF)有关,这是Mac OS x上Swing应用程序的默认设置。

如果你需要Aqua LAF,那么没有太多的选择。您可能需要等待Apple的下一个Java更新(我假设他们会优先修复这个问题,因为这是他们自己的LAF)。你也可以尝试使用Java应用程序捆绑器(即捆绑Oracle JRE而避免使用系统的JRE)。

如果你可以使用不同的LAF,那么你的应用程序应该正常工作。至少对《剪纸》来说是这样的(003的更新导致了一些窗口聚焦问题,004的更新造成了混乱)。

一些选择:

  • 从Java代码(例如Nimbus或Metal)使用Java版本特定的跨平台LAF:

    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 <key><string>值的结束。选项是用空格分隔的,就像终端一样。例如,如果你已经有一个useScreenMenuBar选项:

    <key>VMOptions</key>
    <string>-Dcom.apple.macos.useScreenMenuBar=true -Dswing.systemlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel</string>
    


编辑:@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();
                }
            }
        });
    }
}

此问题已通过Apple发布这些更新的修订版本得到解决:http://support.apple.com/kb/DL1572 (10.7, 10.8+)10.6 http://support.apple.com/kb/DL1573(只有)

您过去可以从Swing线程外部调用UIManager.setLookAndFeel()。通过设置调用的外观来启动应用程序可能是非常常见的。Swing API文档说,您可以从该线程外部调用的惟一Swing方法是在方法的JavaDoc中标记为线程安全的的方法。setLookAndFeel没有标记为thread-safe。由于它在调用时不涉及显示任何内容,并且它总是工作,我敢打赌许多人认为它是在实际做任何GUI之前设置一些配置设置的一种方式,并且简单地调用它一次并忘记它。

尝试用与所有其他Swing方法相同的方式包装对UIManager.setLookAndFeel的调用,以确保它在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();
            }
        }
    });

最新更新