Java for OS X 2013-004对Swing应用程序有何影响(中断)?

4
似乎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

你在Swing EDT之外进行任何UI处理吗? - Steve Kuo
我想可能有一些UI调用会悄悄地进入其他线程,但是应用程序在没有更新的情况下运行良好。 - Peter Tseng
请参考此答案 - trashgod
3个回答

3

更新2013-06-21:本答案包含一些有用的解决方法和替代方法,但是@sidney-markowitz-biomatters' answer 包含了正确的代码修复 - LAF 需要在事件线程中设置!

最近出现的问题似乎与更新破坏了Aqua外观(LAF)有关,这是Mac OS X上Swing应用程序的默认外观。

如果您需要Aqua LAF,则没有太多选择。您可能需要等待苹果的下一个Java更新(我假设他们会优先修复此问题,因为这是他们自己的LAF)。您还可以尝试使用Java Application Bundler(即捆绑Oracle JRE并避免使用系统的JRE)。

如果您可以使用不同的LAF,则您的应用程序应该按照正常方式工作。至少对于PaperCut是这样的(003更新导致了一些窗口焦点问题,004更新导致了混乱)。

一些选项:

  • Using the Java version-specific cross platform LAF from Java code (e.g. Nimbus or Metal):

    UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName())
    
  • Setting a specific LAF from Java code:

    UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel")
    
  • Overriding the default LAF from terminal:

    java -Dswing.defaultlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel MyApp
    
在我们的案例中,我们在代码中明确调用了UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()),并且希望有一个不需要改变代码(即热修复)的解决方法,因此我们需要按如下方式覆盖默认的系统 LAF。
  • Overriding the system LAF from terminal:

    java -Dswing.systemlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel ...
    
  • Overriding the system LAF from an Info.plist file (if you have bundled as a Mac application, also works for the other VM options) (e.g. at My.app/Contents/Info.plist).

    You want to add -Dswing.systemlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel to the end of the <string> value for the VMOptions <key>. The options are space separated, just like from the terminal. E.g. if you already have a useScreenMenuBar option:

    <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更新的苹果JRE运行(例如在 /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home)。观察到消息不可见,对话框图标不可见,按钮也不可见。

  2. 使用旧版苹果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();
                }
            }
        });
    }
}

我无法重现这种效果。你能引用一个参考文献或者提供一个 sscce 来展示你所描述的问题吗? - trashgod
有趣的是,我正在使用Aqua,所以我会看看改变外观是否有影响。但是我们不能使用Nimbus L&F发布,所以我可能不得不将JRE捆绑到应用程序中,这也是Oracle推荐的。 - Peter Tseng
+1 用于更新;另请参见Initial Threads - trashgod

2
以前可以在Swing线程之外调用UIManager.setLookAndFeel(),但现在不行了。很可能在应用程序开头使用此调用来设置外观和感觉。Swing API文档表示,您只能从外部调用标有方法JavaDoc中线程安全标签的Swing方法。setLookAndFeel没有标记为线程安全。由于调用时不涉及显示任何内容并且一直有效,因此我敢打赌许多人认为这是在实际执行任何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();
            }
        }
    });

太好了!谢谢。我将编辑我的答案,指向你的答案作为正确答案,但是我也想添加一个重现方法来展示应该如何完成(在事件线程上)。如果你更喜欢把这个加入到你的答案中,请告诉我。 - Tom Clift
@TomClift,我们有一些实用程序类,用于轻松包装Swing调用以确保它在正确的线程中。我假设编写Swing应用程序的大多数人都有类似的东西。如果您有一个简单的独立示例,可以正确调用setLookAndFeel,请继续。顺便说一句,当我修复我们的应用程序时,我特别谨慎,并在包装器中包括了对javax.swing.UIManager.getSystemLookAndFeelClassName() 的调用。至于可重现的测试用例,我还没有找到一种最小的情况来保证失败,有些简单的情况只有有时会失败,我们的真实应用程序总是失败。 - Sidney Markowitz - Biomatters

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接