[an error occurred while processing this directive]

Page One
Page Two
The Databank
What Is Swing?
Special Report
IDE Roundup
Swing and the Web
Swing Text
Tech Topics
Friends
Tips and Tricks
The PLAF Papers
Call 911
The Archive
JFC Home
Download Swing
Swing API Docs
Download JDK
JDK Docs
Java Tutorial
 
The Swing Connection The PLAF Papers
The 'LookandFeel' Class Reference
A PLAF Lookup Guide for Swing Programmers

Java(TM) cup and book

This document is a technical reference for the LookAndFeel class. It lays out the intended use of various portions of the LookAndFeel class, but it is not a tutorial on how to write your own Look and Feel. That will be the topic of a future article in The Swing Connection.




By Steve Wilson

This article is designed for programmers who need to look up the purpose of one or more functions in this class. It can also give some insight into the design decisions that went into Swing's Pluggable Look and Feel (PLAF) mechanism.

Horizontal rule

The LookAndFeel Class

The LookAndFeel class is the staring point for creating your own L&F. To create your own L&F, you must create a subclass of the LookAndFeel class.

The LookAndFeel class has three major responsibilities. These include:

The LookAndFeel class also provides several static utility functions to assist in some of these tasks. These will be discussed later in this article.


Identifying the Look & Feel

One of the main responsibilities of a LookAndFeel derived class is to identify the current L&F. The LookAndFeel classes defines three abstract methods that are used to identify a particular L&F. These are:

   public abstract String getName();
   public abstract String getDescription();
   public abstract String getID(); 

The getName() method is designed to return a string specifying the name of a L&F -- for example "Metal," "Windows," "Joe's Cool Look," or whatever else you want. Itīs best to keep the name of your L&F short, as it might be used in ListBoxes, or Menus to allow a user to choose a L&F.

The getDescription() method allows a L&F to provide a longer text-based description of itself. So your program can call getDescription() to obtain more information that getName() can return.  For example, a look-and-feel might return something like this

"Joe's Cool Look - by Joe - (c) 1998 Joe Inc. All Rights Reserved.  http://www.joeinc.com"

The getID() method is a little trickier. It is provided because there are several reasons that one might want to create a L&F. One developer might create a full-blown corporate L&F, while another might just tweak an existing L&F to customize a few components. If you decide to create a custom look-and-feel is that is completely new, custom L&F, getID() should return some unique string to identify itself. If your homemade L&F just customizes a few parts of an existing L&F, getID() generally should return the same string as the L&F you are subclassing.

This approach allows custom third-party components to decide more intelligently how to display themselves. For example, if your L&F is a subclass of the Motif L&F and  tweaks only a couple of components, you might not want to override the getID() function at all. Then you could ensure that custom components supplied with special appearances for the Motif L&F would still look correct.


Determining Platform Support

Another key responsibility of any LookAndFeel derived class is to provide information related to platform issues. The LookAndFeel class contains two abstract methods that are designed to provide platform-related information:

    public abstract boolean isNativeLookAndFeel();
    public abstract boolean isSupportedLookAndFeel();

The isNativeLookAndFeel() method is provided to determine whether a look-and-feel is designed to emulate the current platform. Obtaining this information often involves a runtime query of the system properties. For example, the MotifLookAndFeel class contains the following code:

    public boolean isNativeLookAndFeel() {
      String osName = System.getProperty("os.name");
      return (osName != null) &&
               (osName.indexOf("Solaris") != -1);
    }

This code snippet returns true if it finds the string Solaris in the string contained in the os.name property. You could write this kind of code for a look-and-feel thatīs designed to emulate a particular platform (for example, BeOS, GEOS, or Amiga). On the other hand, if you design a cross-platform L&F that doesn't emulate any native OS, isNativeLookAndFeel() should always return false.

The UIManager checks the isSupportedLookAndFeel() method  before a look-and-feel is loaded. If isSupportedLookAndFeel() returns false, the L&F hasnīt been loaded. There are a number of reasons why a L&F might not want to run on a particular platform. For example, the L&F might not be written in 100% Pure JavaTM; instead, it might depend on platform-specific features. There may also be competitive or legal reasons for restricting the use of a L&F to certain platforms.


Building a Defaults Table

One critical responsibility of a LookAndFeel subclass is to create a Defaults Table. In Swing, a Defaults Table is a set of Key-Value pairs stored in a UIDefaultsapi object. The LookAndFeel class defines a single function in charge of creating the defaults table.

   public UIDefaults getDefaults()

The defaults table typically consists of three main categories of information:


 

NOTE: If you are building a special purpose L&F for use with the Multiplexing UI system, then you still need to provide a UI Classmap, but the other two categories of information may not be important. If you are creating a full L&F implementation, you should provide all three types.


The UI Classmap

The UIClassmap is built of paired Strings. These pairs are used to associate a subclass of JComponent with a subclass of ComponentUI. Components use this mapping to create their associated UI objects. For each subclass of JComponent, there is a unique String tag to describe that component. To construct each tag, the "J" is removed from the name of its component, and a "UI" suffix is added. There are a few exceptions -- caused by the fact that some UI classes don't have corresponding "J" classes (for example, DesktopIconUI) -- but these are exceptions.

The following table presents a list of tags used in Swing 1.1.

ButtonUI

CheckBoxUI

ColorChooserUI

MenuBarUI

MenuUI

MenuItemUI

CheckBox-
MenuItemUI

RadioButton-
MenuItemUI

RadioButtonUI

ToggleButtonUI

PopupMenuUI

ProgressBarUI

ScrollBarUI

ScrollPaneUI

SplitPaneUI

SliderUI

SeparatorUI

ToolBarSeparatorUI

PopupMenu-
SeparatorUI

TabbedPaneUI

TextAreaUI

TextFieldUI

PasswordFieldUI

TextPaneUI

EditorPaneUI

TreeUI

LabelUI

ListUI

ToolBarUI

ToolTipUI

ComboBoxUI

TableUI

TableHeaderUI

InternalFrameUI

StandardDialogUI

DesktopPaneUI

DesktopIconUI

DirectoryPaneUI

FileChooserUI

OptionPaneUI

 

In a UIClassmap, each entry is composed of a key (one of the tags above) and a value (the fully qualified name of the class which will be used for that component). BasicLookAndFeel provides a special function call initClassDefaults() to assist in building this table. For more information how these values are used, see the archived article titled "A Swing Architecture Overview."

System Colors

Another part of the defaults table defines SystemColors. The System Colors part of the defaults table consists of a series of key-value pairs that map to entries in the java.awt.SystemColor class. A full-blown L&F usually provides this section of the table, but it could be left out of an L&F that is part of an auxiliary L&F designed for use with the Multiplexing L&F system. Here is a list of the system colors, along with a short description of each entry:

  • desktop: Color of the desktop background
  • activeCaption: Color for captions (title bars) when they are active.
  • activeCaptionText: Text color for text in captions (title bars).
  • activeCaptionBorder: Border color for caption (title bar) window borders.
  • inactiveCaption: Color for captions (title bars) when not active.
  • inactiveCaptionText: Text color for text in inactive captions (title bars).
  • inactiveCaptionBorder: Border color for inactive caption (title bar) window borders.
  • window: Default color for the interior of windows
  • windowBorder: Color of the window's border
  • windowText: Color of the window's title text
  • menu: Background color for menus
  • menuText: Text color for menus
  • text: Text background color
  • textText: Text foreground color
  • textHighlight: Text background color when selected
  • textHighlightText: Text color when selected
  • textInactiveText: Text color when disabled
  • control: Default color for controls (buttons, sliders, etc)
  • controlText: Default color for text in controls
  • controlHighlight: Specular highlight (opposite of the shadow)
  • controlLtHighlight: Highlight color for controls
  • controlShadow: Shadow color for controls
  • controlDkShadow: Dark shadow color for controls
  • scrollbar: Scrollbar background (usually the "track")
  • info: information color (sometimes used for tooltips)
  • infoText: information text color (sometimes used for tooltips)

Each entry in this part of the table is composed of a key (one of the strings above) and a value ( a ColorUIResourceapi that describes the color to be used). This BasicLookAndFeel class provides a function called initSystemColorDefaults() to assist in building this section of the defaults table.

Component Defaults

The last section of the defaults table consists of a set of Component defaults. These typically consist of the Colors, Fonts, and Icons used in each type of component. A full-blown L&F usually provides this section of the table, but it could be left out of an L&F that is part of an auxiliary L&F designed for use with the Multiplexing L&F system. Each component in your L&F will probably provide several several entries. For example the keys for these entries might look like this:

  • Button.background.
  • Button.foreground.
  • Button.font.
  • Button.border.

Each value for an associated key should consist of an object which is a subclass of UIResourceapi (link to UIResource stuff here).  This BasicLookAndFeel class provides a function called initComponentDefaults to assist in building this section of the defaults table.


UIResources

Application developers and L&F developers use the same methods to effect the state of components. The UIResource interface is used to differentiate Colors, Fonts, Borders and other objects created by the L&F from similar objects created by the application developer. Most objects installed by the L&F are "tagged" with the UIResource interface. L&F classes can use the instanceof keyword to determine if a given object was installed by the application or the L&F. Values installed by the application typically take precedence over values installed by the L&F. Note that the UIResource interface defines no methods. UIResource is a pure "tagging" interface.

Several subclasses of UIResource areprovided for the convenience of L&F developers.  These include:

  • ColorUIResource
  • FontUIResource
  • BorderUIResource
  • IconUIResource
  • DimensionUIResource
  • InsetsUIResource

UIResource-derived objects are typically stored in the defaults table, which is accessed through the UIManager.

One function is the single bottleneck point for accessing the defaults table:

    public static Object get(Object key)

This function returns type Object; however, the UIManager also provides several convenience methods for accessing the defaults table in a type-safe manner. These include:

   public static Font getFont(Object key)
   public static Color getColor(Object key)
   public static Icon getIcon(Object key)
   public static Border getBorder(Object key
   public static Insets getInsets(Object key) 
   public static Dimension getDimension(Object key)

Note that there are two additional functions provided by the UIManager class htat are in a slightly different category. While these are type-safe ways to access the defaults table, they do not return subclasses of UIResource.

   public static String getString(Object key)
   public static int getInt(Object key)

These functions donīt return UIResource subclasses because both java.lang.String and java.lang.Integer are "final" and cannot be subclassed. That means they cannot be tagged with the UIResource interface. Consequently, L&F developers must use other mechanisms other than the UIResource tag to determine the origin of such objects.

[an error occurred while processing this directive]