Swing GUI does not show or show with errors when launched on Mac
Asked Answered
P

2

7

I have a Java Swing project which works fine on both Windows and Ubuntu. I did not have any Macs so I could not test it; I have used the Nimbus theme as the standard for this project.

Now, recently my friend tested the same project both in Eclipse and exported jar, and it is giving errors that do not refer to any specific Java class that I have made.

It does show the GUI, but sometimes it sticks, or sometimes menus are missing.

Here is a stripped down version of errors shown while launching the GUI:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at com.apple.laf.AquaMenuPainter.paintMenuBarBackground(AquaMenuPainter.java:123)
    at com.apple.laf.AquaMenuUI.paintBackground(AquaMenuUI.java:57)
    at com.apple.laf.AquaMenuPainter.paintMenuItem(AquaMenuPainter.java:160)
    at com.apple.laf.AquaMenuUI.paintMenuItem(AquaMenuUI.java:35)
    at javax.swing.plaf.basic.BasicMenuItemUI.paint(BasicMenuItemUI.java:452)
    at javax.swing.plaf.basic.BasicMenuItemUI.update(BasicMenuItemUI.java:448)
    at javax.swing.JComponent.paintComponent(JComponent.java:752)
    at javax.swing.JComponent.paint(JComponent.java:1029)
    at javax.swing.JComponent.paintChildren(JComponent.java:862)
    at javax.swing.JComponent.paint(JComponent.java:1038)
    at javax.swing.JComponent.paintChildren(JComponent.java:862)
    at javax.swing.JComponent.paint(JComponent.java:1038)
    at javax.swing.JLayeredPane.paint(JLayeredPane.java:567)
    at javax.swing.JComponent.paintChildren(JComponent.java:862)
    at javax.swing.JComponent.paint(JComponent.java:1038)
    at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:34)
    at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:60)
    at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:97)  

Could you tell me what could be the problem, or is there any specific Look and Feel theme I should be using on Mac? Is Nimbus not supported on Mac and if so then what should I use?

Proprietor answered 24/4, 2012 at 15:43 Comment(3)
Ok if i change the theme to "Aqua" it starts working, so my question should be rather removed and i want to ask how to detect in java, if the underlying OS is MAC??Proprietor
IMHO, you don't touch look and feel on a Mac. The Aqua theme by Apple is awesome. Apple did it that way that you even don't have to set the look and feel. It will be automatically Aqua instead of Sun Swing Metal.Carpology
@MartijnCourteaux, true but i am running across problem with the same code running on MAC, when i have explictly set the Look & Feel to "Nimbus", or is it that i will have to remove this assignment??Proprietor
C
7

I wouldn't touch the theme in OS X, it is awesome automatically :D

Just make sure you don't change the theme when you are on Mac.

String osName = System.getProperty("os.name").toLowerCase();
if (!osName.contains("mac")) // if not on mac
{
   // set nimbus
}
// otherwise, do nothing. It goes automatically to Aqua.
Carpology answered 24/4, 2012 at 15:50 Comment(0)
F
1

Hard to believe, but I hit this wall yesterday, 10+ years later. A similar exception within the same method. In my case, it happened when trying to display a JDialog that happens to have a JMenuBar set on MAC OSX. That JMenuBar is the root cause for the issue.

We are using a custom dark theme L&F (Bulenkov's Darcula) that's (if I'm not mistaken) based on Aqua on MACs. You can have the same L&F in Netbeans, which is why you come across questions like this one.

In my case, there were properties missing in UIManager for "MenuBar.backgroundPainter" and "MenuBar.selectedBackgroundPainter". Both are expected to be set to a border instance. The souce code where the NPE occurred looked something like this:

    static class RecyclableBorder extends RecyclableSingleton<Border> {
        final String borderName;
        RecyclableBorder(final String borderName) { this.borderName = borderName; }
        protected Border getInstance() { return UIManager.getBorder(borderName); }
    }

    private static final RecyclableBorder menuBarPainter = new RecyclableBorder("MenuBar.backgroundPainter");
    private static final RecyclableBorder selectedMenuBarItemPainter = new RecyclableBorder("MenuBar.selectedBackgroundPainter");
    private static final RecyclableBorder selectedMenuItemPainter = new RecyclableBorder("MenuItem.selectedBackgroundPainter");

    public void paintMenuBarBackground(final Graphics g, final int width, final int height, final JComponent c) {
        g.setColor(c == null ? Color.white : c.getBackground());
        g.fillRect(0, 0, width, height);
        menuBarPainter.get().paintBorder(null, g, 0, 0, width, height); // NPE on .get()
    }

So setting the two properties conditionally for MAC OSX and dark theme worked around that.

UIManager.put("MenuBar.backgroundPainter", BorderFactory.createEmptyBorder());
UIManager.put("MenuBar.selectedBackgroundPainter", BorderFactory.createEmptyBorder());

The thing is, you are not supposed to have JMenuBar instances on a MAC. Not the ones that are painted inside a Window. You are supposed to move those via System.setProperty("apple.laf.useScreenMenuBar", "true") like shown here. Unfortunately, that doesn't seem to work for JDialogs, JFrames only, despite using JDialog.setJMenuBar(JMenuBar).

Firecure answered 5/7 at 8:47 Comment(1)
Yes, I encountered this exact NPE when upgrading from JDK 8 to JDK 21 on MacOS + Nimbus look and feel. Thank you for the solution and commentary/link!Gui

© 2022 - 2024 — McMap. All rights reserved.