Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
951 views
in Technique[技术] by (71.8m points)

macos - How does Java for OS X 2013-004 affect (break) Swing applications?

It seems like Java for OS X 2013-004 (Java 1.6.0_51) breaks some Swing applications: https://discussions.apple.com/message/22279872?tstart=0#22279872?tstart=0 http://www.mathworks.com/matlabcentral/answers/79489

My app loads, but it doesn't repaint normally. Clicking on buttons and other operations actually seem to work, but the display only gets updated if the frame is resized - really bizarre.

Does anyone have any idea what the problem could be?

Edit: Seems like Apple fixed it: http://lists.apple.com/archives/java-dev/2013/Jun/msg00055.html

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Update 2013-06-21: this answer contains some workarounds and alternatives that may be useful, but @sidney-markowitz-biomatters' answer contains the correct code fix - the LAF needs to be set from the event thread!

The recent problems seem to be related to the updates breaking the Aqua Look and Feel (LAF), which is the default for Swing apps on Mac OS X.

If you need the Aqua LAF then there are not too many options. You might need to wait for the next Java update from Apple (I'm assuming they will fix this with priority, given it's their own LAF). You could also try using the Java Application Bundler (i.e. bundle the Oracle JRE and avoid using the system's JRE).

If you can get by with a different LAF then your app should work as normal. It did for PaperCut, at least (the 003 update caused some window focus problems, the 004 update caused mayhem).

Some options:

  • 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
    

In our case we were explicitly calling UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()) in our code and wanted a workaround that didn't involve a code change (i.e. a hotfix), so we needed to override the default system LAF as follows.

  • 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>
    


Edit: @trashgod asked for a reproducible example. I'm not sure what the full scope of the problems with the 004 update are, but here's a simple reproduction:

Update 2013-06-21 - the wrong way, reproducing the error:

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. Run with the Apple JRE that comes with the 004 update (e.g. at /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home). Observe that the message is not visible, the dialog icon is not visible and the button is not visibly clickable.

  2. Run with an older Apple JRE or another JRE. Observe that the dialog displays as expected.

Update 2013-06-21 - the right way, on the event thread, works correctly:

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();
                }
            }
        });
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...