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.