Before i start discussing the different implementations of validation overlays that illustrate the power and flexibility of the Swing rendering pipeline, i want to mention some of the common classes that will be used throughout this series. First, here is the screenshot of the sample UI that will be used for all the techniques:

Validation overlays groundworks

Note that the code focuses on the painting itself, and leaves the custom validation logic (based on the contents of the text field, selected combobox entry etc) to the application code (which is not relevant for discussing the Swing painting pipeline). The common classes are located in the <a href="https://pushingpixels.dev.java.net/source/browse/pushingpixels/src/org/pushingpixels/validation/">org.pushingpixels.validation</a> and <a href="https://pushingpixels.dev.java.net/source/browse/pushingpixels/src/org/pushingpixels/validation/common/">org.pushingpixels.validation.common</a> packages that contain the following:

  1. The SampleUi class is the UI itself. It uses the FormLayout to create a simple two-column layout with a few controls.
  2. The common.ValidationUtils provides a very simple implementation of two helper methods. The first is hasError(Component c) that returns boolean indication whether the specified component should show the error overlay. The second is the paintErrorIcon(Component c, Graphics g, int x, int y) that paints small error icon at the specified location. More on these two methods below.
  3. The ComponentVisitor interface follows the usual visitor pattern to allow some of the discussed implementations to visit all components starting from a specific root.
  4. The Visitor class implements the visitor pattern itself, with the static void visit(ComponentVisitor visitor, Component c, Graphics g) method that recursively visits the entire hierarchy of the specified component, calling the custom visitor logic on each one of the children components.

Note that the first two would be application-specific, and the last two are relevant only for some techniques.

In addition, using the visitor pattern reveals one of the weaker sides of Swing. The basic JComponent class extends Container, which means that every core Swing component can have children components. While it allows some nifty tricks like putting a JOGL-powered icon on a button, it unnecessarily exposes the application code to the implementation details of some more complex components. For example, an editable JComboBox is implemented with a text field and a button. A JSpinner is implemented as a text field and two buttons. Unfortunately, these are counted in the getComponentCount() and returned in getComponent(int index), which makes it rather annoying for the visitor pattern.

Subsequently, the sample implementation of the hasError(Component c) method in common.ValidationUtils makes special checks when it is passed a text field. If the text field has either combobox or spinner parent, it is ignored.

The next entry will show the first extension point in the Swing rendering pipeline – the repaint manager.

In my presentation at OSCON 2007 (PDF slides available) i talked about the Swing painting pipeline and how easy it is to extend it to provide custom painting behavior and effects. In this series i’m going to talk about these extension points in a more detailed way, taking you on a journey along a very well-engineered and extensible implementation that makes Swing one of the best available UI toolkits.

The following two images show a high-level overview of the Swing painting pipeline which consists of three major players, the JComponent, the RepaintManager and the ComponentUI:

Swing painting pipeline 1

Swing painting pipeline 2

As i mentioned in the presentation, pretty much everything you see in this pipeline is extensible, which makes it very easy to override / extend the basic core implementation and to provide your own custom painting. These extension points (or hooks) vary in three main areas: flexibility, robustness and ease of use.

By flexibility i mean the degree of control exposed by the specific hook. For example, if you want to add drop shadows to all your labels, it’s very easy to do with the UI delegates, but next to impossible with other techniques (such as glass pane, for example, especially for anti-aliased texts). By robustness i mean how sure can you be that your custom code works as expected across different operating systems and JDK versions. In addition, this includes the “stability” itself of the custom logic. For example, the repaint manager is a singleton, and you can have two or more application modules fighting to install their own implementation. Finally, by ease of use i mean the complexity of the implementation itself. While the repaint manager is, in most cases, the hardest to implement, providing custom painting logic with glass pane or by overriding paintComponent might be considered the easiest.

The techniques will be discussed and compared using the following common task – provide validation indication on different controls. The validation indication itself will be painted as a small error icon in the top-left corner of the “invalid” component; in addition, any Swing component can be in the invalid state. The later includes, for example, simple text fields and editable comboboxes (which contain child components as the implementation detail).

The following techniques will be shown (links will be added as each technique is described):

  1. Repaint manager
  2. Overriding paint() manually
  3. Using AOP to override paint()
  4. Custom border
  5. Layered pane
  6. Glass pane
  7. JXLayer
  8. Extending look and feel
  9. Multiplex look and feel

See you in the next entries.

JTree component is very well suited for showing the contents of your file system. In this entry, i’m going to show how you can do it, pointing out a few interesting issues along the way.

The full source for this example can be found here. It contains the following functionality:

  • The FileSystemView object to query the contents of the local file system.
  • The FileTreeCellRenderer to render the single file cell. It has two caches, one for storing the file icon, and another for storing system name for file system root. The second one if very important for performance since on some systems the call to FileSystemView.getSystemDisplayName can take considerable time. Note how we use the FileSystemView.getSystemIcon to show the system-consistent file icon (see screenshot below).
  • The FileTreeNode to present a single tree node. Note that the JTree implementation will not create the entire model (which is very good for the initial state where all the file system roots are collapsed).
  • The main panel that creates the tree, sets the model and the renderer and wraps the tree in a scroll pane. Note that we use File.listRoots to get the file system roots and JTree.setRootVisible(false) to remove the main tree root (so that we have “multi-root” tree, with each file system root being a top-level tree node) – see screenshot below.

Here is how it looks:

File tree panel

This is the fourth part in the ongoing series about advanced animations on core Swing component built-in to the latest binary drops of Substance look-and-feel.

  • The first part showed rollover and selection background animations on menus, sliders, tables and table headers
  • The second part showed rollover foreground animations on menus under a skin that uses dark background fill on menubars
  • The third part showed rollover and selection background and foreground animations under a mixed dark-light theme

This part demonstrates the animations under the new Magma skin. Unlike other mixed dark-light skins (Nebula, Nebula Brick Wall and Business Black Steel), pretty much all animations under Magma feature dark-light transitions for both background and foreground colors. Here is a sample video that shows animation effects on buttons, toggle buttons, checkboxes and radio buttons (note that for the later two, the foreground is not animated):


The next video shows rollover animation effects on Magma sliders:

The last video shows a complex rollover animation effect on Magma tabs. Substance provides support for tab close buttons. When installed, Substance shows the close buttons on the currently selected and the currently rolled over tab. On rolled over tabs, the close button is faded as the mouse moves over the tabbed pane. For Magma, this means that the close button animation has two channels – during the fade in, the color fades from white to black, and the alpha fades from 0.0 to 1.0. During the fade out, the color fades from black to white, and the alpha fades from 1.0 to 0.0. The video shows the rollover animation sequence under very slow animation speed so you can follow this effect:
You can run a test WebStart application by clicking the button below. The application is signed and requires read-only access to the local disk (for the filetree). In order to switch to Magma, go to the Skins menu and select “Magma”.