Sexy Swing App – The Unified Toolbar

May 2, 2008

The unified toolbar was introduced in Tiger, and provides a distinctive look to Mac applications. Apps written for the Mac that don’t incorporate this feature tend to look decidedly “un-Mac”. Adding this prominent user interface element to your Swing UI is an easy way to give a great first impression.

With the release of Mac OS X 10.5, and Java 1.5.0_13, we Java developers gained a number of client properties, outlined in TN-2196. We’re particularly interested in apple.awt.brushMetalLook, which previously existed and was updated to paint a unified background instead of the old brushed metal look. Using this property, and a transparent component, it’s easy to create a unified toolbar in Swing.

First, set this client property:

// set custom OS X 10.5 client property.
frame.getRootPane().putClientProperty("apple.awt.brushMetalLook", Boolean.TRUE);

Next, add a custom JPanel that looks something like this:

public class UnifiedToolbarPanel extends JPanel {

    public static final Color OS_X_UNIFIED_TOOLBAR_FOCUSED_BOTTOM_COLOR =
            new Color(64, 64, 64);
    public static final Color OS_X_UNIFIED_TOOLBAR_UNFOCUSED_BORDER_COLOR =
            new Color(135, 135, 135);    

    public UnifiedToolbarPanel() {
        // make the component transparent
        setOpaque(false);
        // create an empty border around the panel
        // note the border below is created using JGoodies Forms
        setBorder(Borders.createEmptyBorder("3dlu, 3dlu, 1dlu, 3dlu"));
    }

    @Override
    public Border getBorder() {
        Window window = SwingUtilities.getWindowAncestor(this);
        return window != null && window.isFocused()
                ? BorderFactory.createMatteBorder(0,0,1,0,
                        OS_X_UNIFIED_TOOLBAR_FOCUSED_BOTTOM_COLOR)
                : BorderFactory.createMatteBorder(0,0,1,0,
                       OS_X_UNIFIED_TOOLBAR_UNFOCUSED_BORDER_COLOR);
    }
}

The key to our unified toolbar panel is making it transparent (not opaque) so that Leopard’s frame rendering shows through. Note also that we don’t need to influence the height of the unified toolbar, as there are no strict guidelines on this.

The border is created using JGoodies Forms so that we can use dialog units (DLUs) as a unit of measure – this will ensure that our UI gracefully enters the world of resolution independence. Also notice the bottom border color changes with the focus of the window – this is subtle but key detail in making a believable unified toolbar.

To make your toolbar actually useful, you can add textured buttons with icons. Make sure your icons match the OS X look – you’ll find the guildlines pretty well spelled out in the Apple Human Interface Guidelines.

In the screen shot of the Finder unified toolbar below, you’ll notice that selected icons are white with a dark gray shadow down-shifted by a pixel. Unselected icons are the inverse – dark gray with a semi-transparent white shadow down-shifted by a pixel. Icons in textured buttons are typically monochrome (though sometimes they can have the blue backlit effect).

I created my icons (   ) following this format using Adobe Fireworks.

I used a similar shadowing style to create the button group label, “View”. It isn’t just a simple JLabel, but includes a semi-transparent white shadow down-shifted by a pixel (see the above screen shot from the Finder). You can acheive this affect with an extended JLabel that looks like this:

public class EmphasizedLabel extends JLabel {

    private boolean fUseEmphasisColor;

    public static final Color OS_X_EMPHASIZED__FONT_COLOR =
            new Color(255,255,255,110);
    public static final Color OS_X_EMPHASIZED_FOCUSED_FONT_COLOR =
            new Color(0x000000);
    public static final Color OS_X_EMPHASIZED_UNFOCUSED_FONT_COLOR =
            new Color(0x3f3f3f);

    public EmphasizedLabel(String text) {
        super(text);
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension d = super.getPreferredSize();
        d.height += 1;
        return d;
    }

    @Override
    public Color getForeground() {
        Color retVal;
        Window window = SwingUtilities.getWindowAncestor(this);
        boolean hasFoucs = window != null && window.isFocused();

        if (fUseEmphasisColor) {
            retVal = OS_X_EMPHASIZED__FONT_COLOR;
        } else if (hasFoucs) {
            retVal = OS_X_EMPHASIZED_FOCUSED_FONT_COLOR;
        } else {
            retVal = OS_X_EMPHASIZED_UNFOCUSED_FONT_COLOR;
        }

        return retVal;
    }

    @Override
    protected void paintComponent(Graphics g) {
        fUseEmphasisColor = true;
        g.translate(0,1);
        super.paintComponent(g);
        g.translate(0,-1);
        fUseEmphasisColor = false;
        super.paintComponent(g);
    }
}

We have to be little sneaky in the getColor method, as we can’t actually call setPaint from the paintComponent, lest we end up in a recursive loop of repaints. Also notice above that we’re taking great care to take into account the focus state of the containing Frame.

Good luck creating your own unified toolbar. I’d love to see links from your own apps that take advantage of this new capability in Swing.

Its all about the detail!

32 Responses to “Sexy Swing App – The Unified Toolbar”

  1. Ken Says:

    FYI…I’ve submitted an enhancement request to Apple to provide a client property on a JLabel that renders an “emphasized label”.


  2. […] header in Swing by creating a TableCellRenderer that extends EmphasizedLabel (demonstrated in the Part 1 of this blog series). This renderer can then be installed as the default renderer for the […]

  3. Uwe Says:

    Hi Ken, great work on the details to make it look believable!
    I’ve basically been doing the same thing, but didn’t make my own “emphasized label”. Looks like that: http://img338.imageshack.us/img338/2356/prefskd1.png

    I ran into the problem that the “apple.awt.brushMetalLook” client property didn’t work when I used JDialog instead of JFrame. I was about to post to the Java-dev mailing list when I found your blog post. Maybe you have a clue why it doesn’t work…

    Uwe

  4. Ken Says:

    Hi Uwe,

    I like your preferences pane…looks great!

    I’ve never tried using the apple.awt.brushMetalLook client property on a JDialog. I would probably post to the Apple Java-dev mailing list (as you were planning on doing).

    -Ken

  5. Jeremy Wood Says:

    Clever trick with the JLabel. :)

    An alternative approach to the the lines about the window focus is to add a PropertyChangeListener to the JLabel listening to the “Frame.active” property. (At least that’s commonly updated on Mac; I don’t have a Windows or Linux machine handy to compare against…)

  6. Ken Says:

    Great tip Jeremy! I like your technique better than mine as it doesn’t require extension – I’ll give it a try.

    -Ken


  7. […] first one is aimed at Swing, and creates a unified toolbar lookalike to embed in standard JFrame instances. […]


  8. […] 18, 2008 A little while back, I talked about creating a Unified Toolbar. In that post I included a class called an EmphasizedLabel, which was an extension of JLabel that […]


  9. […] 3, 2008 Thanks to Jeremy Wood’s comment on my Sexy Swing App – Unified Toolbar, I’ve gone back and removed the extension of JPanel I […]

  10. Jeff Says:

    The unified toolbar is working great on java 1.5 but doesn’t display properly with 1.6. Instead of having a nice gradient, it’s only showing a plain dark gray. Does anyone find a workaround to make it work with Java 1.6 ?

    -Jeff

  11. Ken Says:

    Hi Jeff,

    I just tried this out and verified that Java 6 on the Mac does not render the textured window at all. If you create a JFrame and install the textured window client property on the JRootPane (like this: rootPane.putClientProperty(“apple.awt.brushMetalLook”, Boolean.TRUE)) you get an ugly grey rectangle – even when there is no content in the window.

    Try mailing java-dev@lists.apple.com – I’m assuming Mike Swingler will respond telling you to file a bug at http://bugreporter.apple.com .

    -Ken

  12. Harald K. Says:

    Thanks, this is really cool! I’ve tried to achieve the same thing in about a hundred ways that didn’t work, and then this really elegant and easy solution exists… ;-)

    I’ve made a slight hack to make it work on Java 6, painting the gradients myself. Is there a way to get the gradient colors from the system?

    Also, I’ve been thinking maybe this should rather be a custom UI delegate for JToolBar, rather than a component on it’s own?

    .k

  13. Ken Says:

    Hi Harald,

    Glad your finding this component useful! Regarding the Java 6 painting issue…I’m going to email java-dev@lists.apple.com to find out what’s going on with the textured window painting.

    As far as making the UnifiedToolBar into a UI delegate rather than a component: I prefer the encapsulation that the component provides. For example, you can add to the left, middle or right of the toolbar via provided methods. I have made UI delegates for some items in the Mac Widgets for Java project, but most of those are hidden behind factory methods that install the delegates for you.

    Thanks for the feedback Harald!

    -Ken

  14. Jeff Says:

    Hi Ken,

    Thanks for the reply. I took a look to the 10.5.5 Preview 2 known issues and found out that apple is aware of the BrushmetalLook issue: “The apple.awt.brushMetalLook does not render correctly in 64-bit processes”. I just hope they will fix the problem soon.

    Jeff

  15. dyorgio Says:

    Hi man, who you make search field in toolbar?
    this is part of mac Widgets? please, make a post about this component :)

    • Ken Says:

      The search field is courtesy of the client properties supplied by Apple in TN-2196. You’ll have to implement it from scratch if you want the same look on another platform.

  16. dyorgio Says:

    of course…plataform independent :-P

  17. dyorgio Says:

    I already knew these properties. Just thought you made this implementation on your own.
    It would be a good addition to the Mac Widgets? :-)
    Because today like this, use the UnitedBar in windows is horrible.
    I would be happy to help, the more you did not answer the email we sent you with the sample application :-(

  18. Tristan Seifert Says:

    I made a Music Player like iTunes in Java. Here it is:

    http://sourceforge.net/projects/jtunes-online/

    Screenshoots should be somewhere…

  19. biao Says:

    Give me Sexy Swing App – The Unified Toolbar instance source

    thanks…
    xybiao2005@163.com

  20. dan Says:

    hi!

    I just want to ask u how to use your unifiedtoolbar in windows using java…thanks in advance

  21. dan Says:

    hi ken!

    thank you so much for the unified toolbar now I know how to use it in windows…

  22. Doru Chiulan Says:

    hy ken, where i can find the left icons (view type)?
    i want to make the same thing in my project and i’m not so good with photoshop/ilustrator.

  23. Ruben Says:

    Does not work for me. (I´m using Java 7)
    In the technical note says:
    “WARNING: This property must be set before the heavyweight peer for the Window is created. Once addNotify() has been called on the component, causing creation of the heavyweight peer, changing this property has no effect.”
    What that means? i should put it in the controller class that creates the frame or inside de frame`s constructor?

  24. Mike Says:

    This may be a dumb question, but how do you add the JPanel to the JFrame (is there a specific layout/place)


  25. […] followed this tutorial: https://explodingpixels.wordpress.com/2008/05/02/sexy-swing-app-the-unified-toolbar/ to create a native looking toolbar on the mac. The problem might be that I’m not adding it […]


Leave a reply to Ken Cancel reply