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:
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):
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.
SwingX features a very useful API on the JXPanel. The setAlpha allows setting the alpha (translucency / opacity) value for the panel and all its children. For example, if you want all the child components to be painted with 50% translucency, call myJxPanel.setAlpha(0.5f) and you’re done. As a side note, you can have nested JXPanels; in this case the lowest value wins (see the implementation of JXPanel.getEffectiveAlpha). So, if the outer panel has 0.6 alpha, and the inner panel has 0.4 alpha, the children of the inner panel will be painted with 40% opacity (not 0.6*0.4 = 24% opacity).
One case in which you need to be aware of this setting is when you override the paint or paintComponent and use custom composites. In such a case, you need to respect the current composite set on the Graphics object passed to the paint method(s). The current implementation of JXPanel.paint uses the SRC_OVER alpha composite, and if this is what you’re using as well, you can call the following helper method to compute the “combined” composite to set during your custom painting routine:
As you can see, the implementation is pretty straightforward, combining the alpha already set on the Graphics with the one passed to the method. The special case where both are 1.0f simply returns AlphaComposite.SrcOver.
Note that if you’re using a composite different from SRC_OVER, you’ll have to create a temporary image, paint on it and then paint that image back onto the original Graphics (that has the composite of the JXPanel alpha).
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”.