The decoration areas in Substance look-and-feel are, in my view, one of the more powerful features of the library and allow to programmatically implement even the most demanding visual designs in a well-structured way. The lifecycle of Swing UI delegates is not very well suited to using different foreground and background colors on components of the same type in different parts of the same window, and implementing this properly without affecting the performance is an interesting challenge.
The latest binary drops of Substance 5.2dev (code-named Quebec) provide much better support for renderer-based components, such as lists, tables and trees when these are placed in custom Substance decoration areas. To illustrate this, here is a screenshot of a sample application under Substance 5.1 Business Black Steel skin:

There are four different decoration areas, each having one enabled and one disabled list. The visuals are quite jarring – the contrast between even and odd rows (striping) is too high, and the foreground color of odd rows in the top-left enabled list is black (on black background). Here is how the same app looks under Substance 5.2dev:

The next screenshot shows a sample application with tables under Substance 5.1 Business Blue Steel skin:

In addition to the same problems as above, the table header area is not using the correct color schemes (for all areas except NONE). This is how the same app looks under Substance 5.2dev:

Finally, a sample application with trees under Substance 5.1 Nebula Brick Wall skin:

While it looks as expected, it’s only by looking at the skin definition that you can see it’s using wrong background colors for most of the areas – here is how it’s looking under Substance 5.2dev:

The development of the next 5.2 version of Substance (code-named Quebec) is wrapping up. You’re more than welcome to take the latest 5.2dev binary drops for a spin. The release candidate is planned for May 11, with the final release scheduled for May 25.
Color scheme association kinds in Substance look-and-feel are best illustrated by a simple example:

This is a screenshot of a <span style="color: darkblue;">JCheckBox</span>
icon under 72 point font. This checkmark icon has three different visual areas: inner fill, border and the “V” mark. Each one of these areas is painted with a different color scheme, and this is allowed by using the relevant color scheme association kinds.
The <span style="color: darkblue;">org.jvnet.substance.api.ColorSchemeAssociationKind</span>
is the base class for core and custom color scheme association kinds. Where is this class used?
- The first usage is in the skin definition. The main
SubstanceSkin
APIs allow associating different color schemes with different visual areas of Swing controls.
- The specific UI delegates query the component skin for the color schemes that match the relevant visual areas.
Let’s go back to the <span style="color: darkblue;">JCheckBox</span>
icon example above. How do we use the color scheme association kinds to specify three different color schemes for painting this checkmark icon?
As detailed in the skin documentation, each skin has a number of color scheme bundles. This means that two checkboxes with the same model state (selected in out case) can have different visuals, depending on the decoration areas they reside in. In the definition of the specific color scheme bundle, you can specify different color schemes for different component states. This means that a selected checkbox can use colors different from those of a rollover selected checkbox.
In our case, we want to specify different color schemes for different visual areas of selected checkboxes in the default decoration area. The relevant method is the <span style="color: darkblue;">org.jvnet.substance.api.SubstanceColorSchemeBundle</span>
is:
<span style="color: #000000;">registerColorScheme</span><span style="color: #000000;">(</span><span style="color: #000000;">SubstanceColorScheme scheme,</span><span style="color: #ffffff;"> </span><span style="color: #000000;">ColorSchemeAssociationKind associationKind,</span><span style="color: #ffffff;"> </span><span style="color: #000000;">ComponentState... states)</span>
- The inner fill is specified by the
<span style="color: darkblue;">ColorSchemeAssociationKind.FILL</span>
.
- The border is specified by the
<span style="color: darkblue;">ColorSchemeAssociationKind.BORDER</span>
.
- The mark is specified by the
<span style="color: darkblue;">ColorSchemeAssociationKind.MARK</span>
.
Going back once again to the original image:

Here is the outline of the relevant configuration code:
SubstanceColorScheme activeScheme = ...;
SubstanceColorScheme defaultScheme = ...;
SubstanceColorScheme disabledScheme = ...;
SubstanceColorSchemeBundle defaultBundle = new SubstanceColorSchemeBundle(
activeScheme, defaultScheme, disabledScheme);
SubstanceColorScheme selectedBorderScheme = …;
defaultBundle.registerColorScheme(selectedBorderScheme,
ColorSchemeAssociationKind.BORDER, ComponentState.SELECTED);
SubstanceColorScheme selectedMarkScheme = …;
defaultBundle.registerColorScheme(selectedMarkScheme,
ColorSchemeAssociationKind.MARK, ComponentState.SELECTED);
Note that there is no explicit usage of the <span style="color: darkblue;">ColorSchemeAssociationKind.FILL</span>
value. This illustrates the fallback mechanism. In this particular case, the second parameter to the <span style="color: darkblue;">SubstanceColorSchemeBundle</span>
constructor is used as the fallback color scheme for inner fills under all component states. The fallback mechanism also extends to the other color scheme association kinds.
Here is the constructor signature of the <span style="color: darkblue;">ColorSchemeAssociationKind</span>
:
<span style="color: #7f0055;"><strong>public </strong></span><span style="color: #000000;">ColorSchemeAssociationKind</span><span style="color: #000000;">(</span><span style="color: #000000;">String name,</span><span style="color: #ffffff;"> </span><span style="color: #000000;">ColorSchemeAssociationKind fallback</span><span style="color: #000000;">)</span>
The second parameter specifies what should happen when the color scheme bundle definition does not have an explicitly registered color scheme for the specific color scheme association kind under the specific component state.
For example, the <span style="color: darkblue;">ColorSchemeAssociationKind.MARK</span>
has the <span style="color: darkblue;">ColorSchemeAssociationKind.BORDER</span>
as its fallback. This means that if you want to use the same color scheme for painting both borders and marks, you need to only call the <span style="color: darkblue;">SubstanceColorSchemeBundle.registerColorScheme</span>
API with the <span style="color: darkblue;">ColorSchemeAssociationKind.BORDER</span>
value.
The registered associations are used by the Substance UI delegates during the component painting. Specifically for the checkbox, the UI delegate queries the three relevant association kinds (<span style="color: darkblue;">ColorSchemeAssociationKind.FILL</span>
, <span style="color: darkblue;">ColorSchemeAssociationKind.BORDER</span>
and <span style="color: darkblue;">ColorSchemeAssociationKind.MARK</span>
) and uses the relevant painters (gradient and border) to paint the matching visual areas.
Applications that want to provide custom skinning of their UIs can use the following two supported APIs in order to get the relevant color schemes.
First, use the following API in <span style="color: darkblue;">org.jvnet.substance.SubstanceLookAndFeel</span>
class to obtain the skin that should be used for painting your component:
<span style="color: #ffffff;"> </span><span style="color: #7f0055;"><strong>public static </strong></span><span style="color: #000000;">SubstanceSkin getCurrentSkin</span><span style="color: #000000;">(</span><span style="color: #000000;">Component c</span><span style="color: #000000;">)</span>
Then, use the following API in the obtained <span style="color: darkblue;">org.jvnet.substance.api.SubstanceSkin</span>
class to get the color scheme for the relevant visual area:
<span style="color: #ffffff;"> </span><span style="color: #7f0055;"><strong>public </strong></span><span style="color: #000000;">SubstanceColorScheme getColorScheme</span><span style="color: #000000;">(</span><span style="color: #000000;">Component comp,</span><span style="color: #000000;"> ColorSchemeAssociationKind associationKind,</span> <span style="color: #000000;">ComponentState componentState</span><span style="color: #000000;">)</span>
Note that the second method should always return non-<span style="color: darkblue;">null</span>
value, using the fallback mechanism discussed above to return the matching color scheme.
The development of the next 5.2 version of Substance (code-named Quebec) is wrapping up. You’re more than welcome to take the latest 5.2dev binary drops for a spin. The release candidate is planned for May 11, with the final release scheduled for May 25.
While most applications do not benefit from changing the visual appearance (skins) at runtime, it is a valuable tool during the design phase of the project. There are two levels of visual changes for Swing applications – switching to a different look-and-feel by using the UIManager.setLookAndFeel call, or switching to a different skin in the skinnable look-and-feels.
Substance look-and-feel provides a few APIs that allow querying the available skins and changing the skins on the fly. Here is the list of steps that you need to do to add a combobox selector that shows all the available skins and changes the global Substance skin on selection change:
- Use the
getAllSkins()
API to populate the combobox with the list of all available Substance skins.
- Use the
getCurrentSkin()
API to select the combobox entry that matches the current Substance skin.
- Since the model entries behind the combobox are
<span style="color: darkblue;">SkinInfo</span>
objects, extend the default Substance combobox cell renderer to use the display name of the skin.
- Finally, register an action listener on the combobox which gets triggerred on any selection change. The action listener uses the
setSkin(String className)
API to set the selected skin as the new global Substance skin. Note that there is no need to explicitly invoke SwingUtilities.updateComponentTree on all your windows after calling this Substance API.
The complete code is available in the CVS repository. For more information on working with Substance skins, see the updated skin documentation.
The development of the next 5.2 version of Substance (code-named Quebec) is wrapping up. You’re more than welcome to take the latest 5.2dev binary drops for a spin. The release candidate is planned for May 11, with the final release scheduled for May 25.
A few hours ago an interesting changelist has made its way into the JDK 7 Swing branch. It definitely looks like the Nimbus designer will be available as part of JDK 7.
Unfortunately, it does look like this changelist does not contain all the files that are part of Nimbus designer (see below for the walkthrough), but hopefully this will be amended in the following days. In the meanwhile, here is what i’ve been able to do:
- Click on the zip link on the changelist page and extract the contents of the zip file. I’ve saved it in the C:\JTools\jdk7-src folder.
- Create a new Eclipse project. Point to C:\JTools\jdk7-src\jdk-c5cd40f1f596\make\tools\swing-nimbus\classes as source, and add all the jars in C:\JTools\jdk7-src\jdk-c5cd40f1f596\make\tools\swing-nimbus\libs as external jars.
As i said before, it looks like the changelist is not complete, and i haven’t been able to find the main class to run the designer itself. However, you can run the partial generation of Nimbus painters to get the feel of how that phase is working. Here are the steps:
Run the org.jibx.binding.Compile class passing the following two program arguments:
- C:\JTools\jdk7-src\jdk-c5cd40f1f596\make\tools\swing-nimbus\classes\org\jdesktop\swingx\designer\Designer.jibx.xml
- C:\JTools\jdk7-src\jdk-c5cd40f1f596\make\tools\swing-nimbus\classes\org\jdesktop\synthdesigner\synthmodel\SynthModel.jibx.xml
Copy the three .template files from C:\JTools\jdk7-src\jdk-c5cd40f1f596\src\share\classes\javax\swing\plaf\nimbus to C:\JTools\jdk7-src\jdk-c5cd40f1f596\make\tools\swing-nimbus\classes\org\jdesktop\synthdesigner\generator\resources
Run the org.jdesktop.synthdesigner.generator.Generator class passing the following arguments:
- -full false
- -skinFile C:\JTools\jdk7-src\jdk-c5cd40f1f596\src\share\classes\javax\swing\plaf\nimbus\skin.laf
- -srcDir c:\temp\nimbus
- -buildDir c:\temp\nimbus
- -packagePrefix org.nimbus
- -lafName Nimbus
At this point, the c:\temp\nimbus should have the generated painter classes. Note that if you pass the -full true, the generation will fail since some of the template files (such as LookAndFeel.template) are not part of this changelist.