Developer

Using pluggable look-and-feel in Java Swing APIs


The Java Swing API provides a pluggable look-and-feel (PLAF) capability, which allows Swing GUI widgets to change appearance based on the programmer's customized look-and-feel setting. Almost all modern user interface frameworks coalesce the view and controller, whether they are based on SmallTalk, C++, or Java.

Swing packages each component's view and controller into an object called a UI delegate. For this reason, Swing's underlying architecture is referred to as model-delegate rather than a model-view-controller. Ideally, communication between both the model and the UI delegate is indirect, allowing more than one model to be associated with one UI delegate and vice versa.

UI delegates

Each UI delegate is derived from an abstract class called ComponentUI. ComponentUI methods describe the fundamentals of how a UI delegate and a component using it will communicate. Note that each method takes a JComponent as a parameter. ComponentUI has many methods, but here are the most important ones:

  • static ComponentUI createUI(JComponent c): This method is normally implemented to return a shared instance of the UI delegate defined by the defining ComponentUI subclass itself. This instance is used for sharing among components of the same type (e.g., all JButtons using the Metal look-and-feel share the same static UI delegate instance defined in javax.swing.plaf.metal.MetalButtonUI by default).
  • installUI(JComponent c): This method installs this ComponentUI on the specified component. This normally adds listeners to the component and/or its model(s) to notify the UI delegate when changes in state occur that require a view update.
  • update(Graphics g, JComponent c): If the component is opaque, this should paint its background and then call paint(Graphics g, JComponent c).
  • paint(Graphics g, JComponent c): This method gets all of the information it needs from the component and possibly its model(s) to render it correctly.

To enforce the use of a specific UI delegate, you can call a component's setUI() method like this:

JButton m_button = new JButton();

m_button.setUI((MyButtonUI)MyButtonUI.createUI(m_button));

The JComponent class defines methods for assigning UI delegates because the method declarations required do not involve component-specific code. However, this is not possible with data models because there is no base interface that all models can be traced back to (i.e., there is no base class such as ComponentUI for Swing models). For this reason, the methods to assign models are defined in subclasses of JComponent where necessary.

Put PLAF to use

Swing includes several sets of UI delegates. Each set contains ComponentUI implementations for most Swing components, and each of these sets is called a PLAF implementation.

The javax.swing.plaf package consists of abstract classes derived from ComponentUI, and the classes in the javax.swing.plaf.basic package extend these abstract classes to implement the Basic look-and-feel. This is the set of UI delegates that all other look-and-feel classes are expected to use as a base for building off of. The Basic look-and-feel cannot be used on its own because BasicLookAndFeel is an abstract class. There are three pluggable look-and-feel implementations derived from the Basic look-and-feel:

  • Windows: com.sun.java.swing.plaf.windows.WindowsLookAndFeel
  • CDE\Motif: com.sun.java.swing.plaf.motif.MotifLookAndFeel
  • Metal (default): javax.swing.plaf.metal.MetalLookAndFeel

There is also a MacLookAndFeel for simulating Macintosh user interfaces, but this does not ship with Java 2 and must be downloaded separately. The multiplexing look-and-feel, javax.swing.plaf.multi.MultiLookAndFeel, extends all of the abstract classes in javax.swing.plaf. It is designed to allow combinations of look-and-feels to be used simultaneously and is intended for, but not limited to, use with Accessibility look-and-feels. The job of each multiplexing UI delegate is to manage each of its child UI delegates.

Each look-and-feel package contains a class derived from the abstract class javax.swing.LookAndFeel: BasicLookAndFeel, MetalLookAndFeel, WindowsLookAndFeel, etc. These are the central points of access to each look-and-feel package. You use them when changing the current look-and-feel, and the UIManager class (which is used to manage installed look-and-feels) uses them to access the current look-and-feel's UIDefaults table (which contains, among other things, UI delegate class names for each Swing component's corresponding look-and-feel).

To change the current look-and-feel of an application, you can simply call the UIManager's setLookAndFeel() method, passing it the fully qualified name of the LookAndFeel to use. You can use the code in Listing A to accomplish this at runtime.

SwingUtilities.updateComponentTreeUI() informs all children of the specified component that the look-and-feel has changed and that they need to discard their UI delegate in exchange for a different one of the specified type.

Figures A, B, and C illustrate the difference between Metal, Motif, and Windows look-and-feel.

Create a PLAF

Before creating a PLAF, you must decide between two design methods for creating a look-and-feel in Java. One method is to create the look-and-feel by extending the javax.swing.plaf package; the other is to extend an existing look-and-feel package, usually javax.swing.plaf.basic.

It not recommended to extend a look-and-feel from the javax.swing.plaf package if the look-and-feel is going to be for a PC. This is because the javax.swing.basic package has extended almost the entirety of the javax.swing.plaf package for you to use. This allows you to pick and choose which things about the look-and-feel to customize without having to extend and implement everything.

In its implementation of the javax.swing.plaf package, a basic principle is followed that allows for customizing a look-and-feel very easily. This principle is the centralization of components, color, and UI classes within the LookAndFeel class.

The javax.swing.plaf.basic package paints the lightweight Swing components in expected ways. However, the recommendation changes if you're creating a look-and-feel for a device other than the computer screen. Then, the preferred method is extending the javax.swing.plaf package from scratch.

Peter V. Mikhalenko is a Sun certified professional who works for Deutsche Bank as a business consultant.

———————————————————————————————————————————-

Get Java tips in your inbox Delivered each Thursday, our free Java newsletter provides insight and hands-on tips you need to unlock the full potential of this programming language. Automatically subscribe today!

Editor's Picks