Sexy Swing App – The Bottom Bar

June 19, 2008

In the last installment of “Sexy Swing App”, I’ll show you how to create a bottom bar component as defined by Apple in their Human Interface Guidelines here.

There’s not much to this component, just a gradient and a compound line border that changes based on the focus state of the parent window. Below I’ve provided only the code related to the rendering of the bottom bar (i.e. not the code that lays out the bottom bar’s components). Here’s the custom JPanel that handles this rendering:

public class BottomBarPanel extends JPanel {

        private static final Color OS_X_BOTTOM_BAR_ACTIVE_TOP_COLOR =
                new Color(0xbbbbbb);
        private static final Color OS_X_BOTTOM_BAR_ACTIVE_BOTTOM_COLOR =
                new Color(0x969696);
        private static final Color OS_X_BOTTOM_BAR_INACTIVE_TOP_COLOR =
                new Color(0xe3e3e3);
        private static final Color OS_X_BOTTOM_BAR_INACTIVE_BOTTOM_COLOR =
                new Color(0xcfcfcf);
        private static final Color OS_X_BOTTOM_BAR_BORDER_HIGHLIGHT_COLOR =
                new Color(0xd8d8d8);
        private static final Color OS_X_UNIFIED_TOOLBAR_FOCUSED_BOTTOM_COLOR =
                new Color(64, 64, 64);
        private static final Color OS_X_UNIFIED_TOOLBAR_UNFOCUSED_BORDER_COLOR =
                new Color(135, 135, 135);

        public BottomBarPanel() {
            setBorder(BorderFactory.createMatteBorder(1,0,0,0,
                   OS_X_UNIFIED_TOOLBAR_FOCUSED_BOTTOM_COLOR));
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D graphics = (Graphics2D) g.create();

            Window window = SwingUtilities.getWindowAncestor(this);
            boolean hasFoucs = window != null && window.isFocused();

            Color topColor = hasFoucs
                    ? OS_X_BOTTOM_BAR_ACTIVE_TOP_COLOR
                    : OS_X_BOTTOM_BAR_INACTIVE_TOP_COLOR;
            Color bottomColor = hasFoucs
                    ? OS_X_BOTTOM_BAR_ACTIVE_BOTTOM_COLOR
                    : OS_X_BOTTOM_BAR_INACTIVE_BOTTOM_COLOR;

            Paint paint = new GradientPaint(0, 0, topColor,
                    0, getHeight(), bottomColor);

            graphics.setPaint(paint);
            graphics.fillRect(0,0,getWidth(),getHeight());

            graphics.dispose();
        }

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

    }

    public enum Size {

        SMALL(22), LARGE(32);

        private int fHeight;

        Size(int height) {
            fHeight = height;
        }

        public int getHeight() {
            return fHeight;
        }
    }

Notice the top border is actually two single pixel lines – the bottom line acts as an inverse shadow, providing a slight etched look. As I’ve said before, it’s these subtle details that make or break the believability of your user interface.

Also notice that I’ve encapsulated the two size variants of a bottom bar in an enum, which isn’t yet used here. Ideally the bottom bar’s preferred height would be derived from the fHeight property of Size enum.

One parting note – if you prefer, as I do, to reduce the amount of extending your code does, I’d recommend using SwingX. Much of the extending I’ve done in this series can be reduced to Painters in SwingX.

Advertisements

8 Responses to “Sexy Swing App – The Bottom Bar”


  1. Nice work! The one thing this doesn’t implement from the HIG is that the corners should be slightly rounded. This is nasty since it requires a transparent window, but you can probably fake the effect (since it’s such a tiny round anyway) by using a gradient color rather than a hard stroke, thus filling the space from the rounding to the actual corner and subtly tricking the eye. It won’t pass any sort of really close examination, but it might fool the eye in passing.

  2. Ken Says:

    Thanks Daniel! It kills me to see the square corners at the bottom of the “textured” window in Java.

    I’ve thought about trying to implement the rounded corners using a shaped window, but thus far it’s fallen into the too much effort bucket. If I get sufficiently motivated to tackle this issue, I’ll be sure to post about it here.

    I’ll also submit an enhancement request to Apple asking for a client property to draw the rounded corners in order to spare us from this hackery.

    -Ken

  3. Mikael Grev Says:

    The roundness of the status bar is not the responsibility of the status bar itself, it is the responsibility of the windowing system, look&feel or similar.

  4. Ken Says:

    Right…but in the case of a work-around, I’d put the code wherever was easiest in hopes that a supported solution would be introduced.

  5. Felix Says:

    Just some other things:
    The fields OS_X_BOTTOM_BAR_BORDER_HIGHLIGHT_COLOR and OS_X_UNIFIED_TOOLBAR_FOCUSED_BOTTOM_COLOR are duplicate. Works though when you comment them out.
    And the constructor is named BottomBarGradientPanel, but the class itself BottomBarPanel.
    Additionally, the class somehow may not be “static” (I don’t know what that would do and why it’s not allowed).

    When I resolve all that, it gives a window a cool bottom panel. Looks great!

    :-),
    Felix

  6. Ken Says:

    Good catches Felix! Those were some copy and paste errors. I’ve updated the entry.

    -Ken

  7. Daniel Zando Says:

    Is there any chance you will update the bar so it will be slightly rounded? Thanks for the awesome work, though!

  8. Ken Says:

    Hi Daniel,

    I probably won’t be able make the bottom window edges rounded, as that would require installing a window mask, which I’d have to do via JNI. We could put in an enhancement request to Apple, though, requesting a client property to make the rounded corners.

    -Ken


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: