Archive for August, 2008

Nimbus UIManager UIDefaults

Wednesday, August 27th, 2008

Nimbus is completely configured by properties in the UIManager defaults table. In my last blog I showed a simple example of how to skin a single component. This gave you a sneak peek into the power of these properties. Lots of people have asked for a complete list of properties that can be set, well its simple just grab UIManager.getLookAndFeelDefaults() and iterate over the contents of the map and print the keys and values and there you go. Well I am not that cruel so I did the work for you and will include a link to a complete table of them at the end. But before I get to that let me explain how they work.

Nimbus properties follow some rules and you can not only use the property keys that we have added in as default but you can create your own. Nimbus Look and Feel scans the UIDefaults table when ever you add a property with UIManager.put(<<key>>,<<value>>) then updates its internal state. When that new property matches the current state of the component it applies to then it will be applied to that component. Properties cascade like CSS and the most specific matching one is used.
Example:

  • foreground = Color.BLACK
  • Label.foreground = Color.BLUE
  • Label[Disabled].foreground = Color.GRAY
  • "SomeLabel"[Disabled].foreground = Color.WHITE

In these examples foreground applies to the foreground of all regions of all components, Label.foreground applies to only Label components, Label[Disabled].foreground applies to only Label components in the Disabled state. "SomeLabel"[Disabled].foreground applies to all components named “SomeLabel” that are in the disabled state. Hopefully that also explains the different ways you can write a rule to match a Component. The only 2 cases that are not covered here are Component.Region.foreground which lets you specify a sub-region of a component and ComponentA:ChildComponentB.foreground which lets you specify a ChildComponentB contained within ComponentA. You can see many examples of these in the complete table below and then play with writing your own. For example you can use the “name” property of a component in a similar way to “class” in CSS, say naming a bunch of buttons “hotButton” and then specifying new rules for them in the defaults table. I already explained in my last blog how you can override the global defaults on a single instance bases which matches the “style” attribute with HTML CSS.

Colors in Nimbus are derived, which means there are a core set of colors which are constants and all the other colors are calculated from those. This means you can simply change those and the 1000s of other colors that are related and used in the painters will update to reflect the new base color. These colors are shown in the “Primary Colors” section of the table. The colors in the “Secondary Colors” section are derived from those in the “Primary Colors” section but themselves are used as the base colors for other colors. You may need to change the secondary colors to tweak the results of changing the primary ones if you are not happy with the results. You can you derived colors in your own code as well so that you colors can change when the primary colors change. This will allow you to make your application color theme-able idea for white label branding etc. The method you need is on NimbusLookAndFeel called getDerivedColor :

/**
 * Get a derived color, derived colors are shared instances and is color
 * value will change when its parent UIDefault color changes.
 *
 * @param uiDefaultParentName The parent UIDefault key
 * @param hOffset             The hue offset
 * @param sOffset             The saturation offset
 * @param bOffset             The brightness offset
 * @param aOffset             The alpha offset
 * @param uiResource          True if the derived color should be
 *                            UIResource, false if it should not be
 * @return The stored derived color
 */
public Color getDerivedColor(String uiDefaultParentName,
               float hOffset, float sOffset, float bOffset, int aOffset,
               boolean uiResource)

Hopefully the rest will make sense as you read though the table and look at all the examples. After that its just a matter of try playing with some and see what you can do. I hope you see that power in this that Richard Bair and I designed and hoped would be useful. The complete defaults properties table is way to big to include in this post so I have put it on a separate page.

If you would like to see how I made this list, here is the code that creates the html.

Java Icon
NimbusBrowser.java

Skinning a Slider with Nimbus

Wednesday, August 20th, 2008

So time for a example of how to skin a Swing JSlider using the Nimbus Look and Feel and some simple painting code. So this is what we get with the standard Nimbus look slider on a dark grey background.

Slider Default Look

All of the Nimbus skin comes from a set of properties in the UIManager defaults table. The keys we will be changing for this example are:

  • “Slider.thumbWidth”
  • “Slider.thumbHeight”
  • “Slider:SliderThumb.backgroundPainter”
  • “Slider:SliderTrack.backgroundPainter”

You can customize the look for a Component either globally for all instances of the component or locally for a single component instance. To change all sliders globally you can set these properties using UIManager.put(key,value) but in this example I will just set them locally for a single slider. To set UI defaults localy for a single component instance you need to create a UIDefaults map, insert you properties and then set it as a client property on the component:

                JSlider slider = new JSlider(0, 100, 50);
                UIDefaults sliderDefaults = new UIDefaults();
                ....
                sliderDefaults.put(<<key>>,<<value>>)
                ....
                slider.putClientProperty("Nimbus.Overrides",sliderDefaults);
                slider.putClientProperty("Nimbus.Overrides.InheritDefaults",false);

The “Nimbus.Overrides.InheritDefaults” key states if the values in “Nimbus.Overrides” should be merged with the defaults(false) or replace them(true). So next some examples for what properties we should set to skin the slider:

                sliderDefaults.put("Slider.thumbWidth", 20);
                sliderDefaults.put("Slider.thumbHeight", 20);
                sliderDefaults.put("Slider:SliderThumb.backgroundPainter", new Painter() {
                    public void paint(Graphics2D g, JComponent c, int w, int h) {
                        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                        g.setStroke(new BasicStroke(2f));
                        g.setColor(Color.RED);
                        g.fillOval(1, 1, w-3, h-3);
                        g.setColor(Color.WHITE);
                        g.drawOval(1, 1, w-3, h-3);
                    }
                });
                sliderDefaults.put("Slider:SliderTrack.backgroundPainter", new Painter() {
                    public void paint(Graphics2D g, JComponent c, int w, int h) {
                        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                        g.setStroke(new BasicStroke(2f));
                        g.setColor(Color.GRAY);
                        g.fillRoundRect(0, 6, w-1, 8, 8, 8);
                        g.setColor(Color.WHITE);
                        g.drawRoundRect(0, 6, w-1, 8, 8, 8);
                    }
                });

The lets pop that code into a sample app and run it and see what it looks like.

Slider Demo

The original Nimbus slider on the bottom and the skinned one on top, both running in the same application. Here is the source so you can try it your self. Let me know if this was useful and what other examples you would like to see.

Java Icon
SliderSkinDemo.java

A very late “Nimbus is Done” blog!

Wednesday, August 20th, 2008

Wow its been crazy, we have finally finished Nimbus for 6u10 and release candidate is out thereĀ Java 6u10 RC Download, have done Java One and I am now knee deep in Java FX. I have about 10 half completed blogs and just never seem to find the time to finish them. As well as being mega busy with Nimbus and Java FX I have just moved back from California to the UK. Moving is always way too time consuming and expensive.

If you missed our talk and BOF at Java One this year here are the presentations:

Java One 2008 Nimbus Talk PDF

Java One 2008 Nimbus BOF Presentation PDF

A lot of you have been asking about the Nimbus Designer Tool that I demoed at Java One. I have been working at getting it opensourced but it is a slow bureaucratic process so I am sorry. In the mean time I thought I would try and do a couple blogs on how you can skin Nimbus your self with out the tool. It is very easy to do providing you are not worried about getting your hands dirty writing some Java 2D drawing code. You could always use images or a SVG library if you don’t fancy raw Java 2D. I would like to split the designer tool into 2 parts the first part the lets you create a Painter classes with Java 2D drawing code by drawing graphics. The second part would let you assign painters to components and generate the code to populate the UIManager defaults table. But both those parts are not hard to do your self if we help you get started so I will see what I can do.

So just a quick hello to say I am still alive, next to try and post a couple blogs on how to skin Nimbus.

SwingSet 3 with Nimbus