26.2 How Does It Work?
As
you probably already know, each instance of a given Swing component
uses a UI delegate to render the component using the style of the
currently installed L&F. To really understand how things work, it
helps to peek under the hood for a moment to see which methods are
called at a few key points. The first point of interest is component
creation time. When a new Swing component is instantiated, it must
associate itself with a UI delegate object. Figure 26-2 shows the important steps in this
process.
In this figure, we show what happens when a new
JTree component is created. The process is the
same for any Swing component:
First, the constructor calls updateUI( ). Each
Swing component class provides an updateUI( )
method that looks something like this:
public void updateUI( ) {
setUI((TreeUI)UIManager.getUI(this));
}
The updateUI( ) method asks the
UIManager class, described below, for an
appropriate UI delegate object via its static getUI( ) method.
The UIManager consults an instance of
UIDefaults (set up when the L&F was first
installed) for the appropriate UI delegate.
The UIDefaults object goes back to the component
to get the UI class ID. In this JTree example,
"TreeUI" is returned.
UIDefaults then looks up the
Class object for the class ID. In this case, it
finds the MetalTreeUI class.
The static method createUI( ) is called (using
reflection) on this UI delegate class. This static method is
responsible for returning an instance of the UI delegate class. In
some cases, a single instance is shared by all components. In other
cases, a new instance is created each time. In this diagram, we show
a new instance of MetalTreeUI being created and
returned from createUI( ).
At last, the JTree has a UI delegate. The
updateUI( ) method now calls setUI( ).
If a UI delegate was already installed (in this example,
we're creating a new component, so there is no
delegate installed yet), setUI( ) would call
uninstallUI( ) on the old delegate.
setUI( ) now calls installUI( )
on the new UI delegate, passing in the component.
The installUI( ) methods for different components
do different things. Often (as shown here), installUI( ) is used to install listeners (allowing the UI delegate to
keep track of changes made to the component), set defaults (e.g.,
fonts and colors), and add keyboard actions.
Now that the new component has been associated with its UI delegate,
it can use the delegate for all L&F-related operations. The
JComponent base class delegates the following
methods to its UI:
 |
The three size accessors delegate to the UI only if a value has not
been explicitly set on the component itself via a call to
setPreferredSize( ), setMaximumSize( ), or setMinimumSize( ).
|
|
Now let's take a second look under the hood and see
how the delegation of the painting process actually happens. The
process in Figure 26-3 is pretty straightforward.
When the component is asked to update itself, it simply calls
paint( ). Notice that this differs from
java.awt.Component.update( ), which paints the
component's background first. We'll
see why this is important later in this chapter.
The JComponent.paint( ) method (after doing quite
a few other things we won't get into here) calls
paintComponent( ).
paintComponent( ) calls update( ) on the UI delegate.
Here (in ComponentUI.update( )), the background is
painted only if the component is opaque. Then, the paint( ) method is called on the delegate.
The paint( ) method, implemented by the specific
UI delegate classes, gets whatever information it needs from the
component (which it receives as a parameter) and renders the
component.
 |
We've left out a lot of details about the Swing
painting mechanics in this example. If you want to know more about
how this works, refer to the description of
JComponent.paint( ) in Chapter 3. Our goal here is just to understand where the
UI delegate fits in the painting process.
|
|
You should now have a basic understanding of how the Swing component
classes work together with the UI delegates. In the next section,
we'll explore the key classes and interfaces that
make up the PLAF architecture.
|