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");
}
}
使用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();
}
}
});
}
}
此问题已通过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();
}
}
});