LookAndFeel, as the name implies, encapsulates a look and
feel. Beyond installing a look and feel most developers never need to
interact directly with
LookAndFeel. In general only developers
creating a custom look and feel need to concern themselves with this class.
Swing is built upon the foundation that each JComponent
subclass has an implementation of a specific ComponentUI
subclass. The ComponentUI is often referred to as "the ui",
"component ui", or "look and feel delegate". The ComponentUI
subclass is responsible for providing the look and feel specific
functionality of the component. For example, JTree requires
an implementation of the ComponentUI subclass TreeUI. The implementation of the specific ComponentUI subclass is provided by the LookAndFeel. Each
JComponent subclass identifies the ComponentUI
subclass it requires by way of the JComponent method getUIClassID.
Each LookAndFeel implementation must provide
an implementation of the appropriate ComponentUI subclass by
specifying a value for each of Swing's ui class ids in the UIDefaults object returned from getDefaults. For example,
BasicLookAndFeel uses BasicTreeUI as the concrete
implementation for TreeUI. This is accomplished by BasicLookAndFeel providing the key-value pair "TreeUI"-"javax.swing.plaf.basic.BasicTreeUI", in the
UIDefaults returned from getDefaults. Refer to
UIDefaults.getUI(JComponent) for defails on how the implementation
of the ComponentUI subclass is obtained.
When a LookAndFeel is installed the UIManager does
not check that an entry exists for all ui class ids. As such,
random exceptions will occur if the current look and feel has not
provided a value for a particular ui class id and an instance of
the JComponent subclass is created.
Recommendations for Look and Feels
As noted in
UIManager each
LookAndFeel has the opportunity
to provide a set of defaults that are layered in with developer and
system defaults. Some of Swing's components require the look and feel
to provide a specific set of defaults. These are documented in the
classes that require the specific default.
ComponentUIs and defaults
All ComponentUIs typically need to set various properties
on the JComponent the ComponentUI is providing the
look and feel for. This is typically done when the ComponentUI is installed on the JComponent. Setting a
property should only be done if the developer has not set the
property. For non-primitive values it is recommended that the
ComponentUI only change the property on the JComponent if the current value is null or implements
UIResource. If the current value is null or
implements UIResource it indicates the property has not
been set by the developer, and the ui is free to change it. For
example, BasicButtonUI.installDefaults only changes the
font on the JButton if the return value from button.getFont() is null or implements UIResource. On the other hand if button.getFont() returned
a non-null value that did not implement UIResource
then BasicButtonUI.installDefaults would not change the
JButton's font.
For primitive values, such as opaque, the method installProperty should be invoked. installProperty only changes
the correspoding property if the value has not been changed by the
developer.
ComponentUI implementations should use the various install methods
provided by this class as they handle the necessary checking and install
the property using the recommended guidelines.
Exceptions
All of the install methods provided by
LookAndFeel need to
access the defaults if the value of the property being changed is
null or a
UIResource. For example, installing the
font does the following:
JComponent c;
Font font = c.getFont();
if (font == null || (font instanceof UIResource)) {
c.setFont(UIManager.getFont("fontKey"));
}
If the font is
null or a
UIResource, the
defaults table is queried with the key
fontKey. All of
UIDefault's get methods throw a
NullPointerException if passed in
null. As such, unless
otherwise noted each of the various install methods of
LookAndFeel throw a
NullPointerException if the current
value is
null or a
UIResource and the supplied
defaults key is
null. In addition, unless otherwise specified
all of the
install methods throw a
NullPointerException if
a
null component is passed in.