What Is Swing? - 2
Introducing
Swing Architecture
NOTE: This article has three parts. Part 1, "Getting
Started with Swing," introduces the basic fundamentals
of Swing and Swing technology. Part 2, "Introducing Swing
Architecture" (which you are reading now), tells how
Swing Components are designed. Part 3, "Creating
a Swing Applet," presents a tutorial that you can
follow to build your own applet using Swing. |
By Mark Andrews
During
the early stages of Swing´s development, there were widespread reports
that the Swing component set were being designed using something
called MVC (model-view-controller) architecture. As it turns out,
those reports were partly true, but not completely accurate.
MVC architecture is a well-known design for GUI objects that dates
back to the SmallTalk language. Classic MVC architecture divides
each component into three parts: a model, a view, and a controller,
as shown in the following diagram. In classic MVC architecture,
the model manages whatever data or values the component uses --
such as the minimum, maximum, and current values used by a scroll
bar. The view manages the way the component is displayed. And the
controller determines what happens when the user interacts with
the component-- for example, what occurs when the user clicks a
button control.
Swing´s modified MVC design
Classic MVC architecture is simple and elegant, and the Swing
team started designing the Swing component set, they experimented
with using a pure MVC design. But they soon discovered that classic
MVC architecture didn´t work very well in real-world Swing application.
So they wound up basing Swing architecture on a modified adaptation
of the traditional MVC design. To implement Swing components, the
Swing team created a modified MVC design. The component design that
the Swing team eventually settled on is sometimes referred to a
separable model architecture.
In Swing's separable model design, the model part of a component
is treated as a separate element, just as the MVC design does. But
Swing collapses the view and controller parts of each component
into a single UI (user-interface) object. The result is an architecture
that looks like this:
Swing´s separable model architecture was developed because the
creators of Swing found that the traditional MVC design didn't work
well in practical terms in Swing-style components. Why not? Because
the view and controller parts of a traditional MVC-based component
require a tight coupling that is sometimes difficult to achieve
in practical terms. For example, traditional MVC architecture makes
it very hard to create a generic controller that doesn't know at
design time what kind of view will eventually be used to display
it.
To developers of Swing applets and applications, this is a big
advantage. With Swing, it's easy to present complex data structures
user in an attractive easy-to-understand way.
Under the following subheadings, each element shown in the precooking
picture is described in more detail.
The UI Manager
To handle the look-and-feel characteristics of its modified-MVC
components, Swing defines a class called the UIManagerapi,
which always keeps track of the current look and feel and its defaults.
The UI manager, shown on the right in the preceding
diagram, controls the look-and-feel capabilities of each Swing
component by communicating with the component's UI object, as shown
in the diagram.
The UI Delegate
In
the Swing API, the name of each generic component class is preceded
by a "J" -- for example, classes in the Swing set are
named JButton, JTree, JTable, and so on. Each generic component
class handles its own individual own view-and-controller responsibilities.
But, as shown in the preceding diagram,
each class delegates the look-and-feel-specific aspects of its responsibilities
to whatever UI object the currently installed look-and-feel provides.
For this reason, the UI object that's built into every Swing component
is sometimes referred to as the UI delegate.
The ComponentUI Class
In Swing, all UI delegate classes are derived from a superclass
named ComponentUIapi.
This class contains most of the important machinery for making Swing's
pluggable look-and-feel work. Its methods deal with UI installation
and uninstallation, and with delegation of a component's geometry-handling
and painting. Delegate UIs are described in more detail later, in
the Pluggable Look and Feel section of this
article.
The Component Model Interface
In component design circles, it´s generally considered good practice
to center the architecture of an application around its data rather
than around its user interface. To support this paradigm, Swing
defines a separate model interface for each kind of component that
can store or manipulate values or data. This separation provides
Swing programs with the option of plugging in their own customized
model implementations.
Default and Custom Component Models
If an application doesn´t explicitly provide its own model implementation
for a particular component, Swing creates and installs a default
model implementation which implements that component's model interface.
For example, when you create a slide-controller component by instantiating
an object of the JSliderapi class,
Swing creates and installs a default model interface that an application
can use to set a maximum value, a minimum value, and a current value
for the control. These values can be set in the control's constructor,
as follows:
this.model =
new DefaultBoundedRangeModel(value, 0,
min, max);
When a Swing component
defines a model, it does so by using a JavaBeansTM bound
property for the model. For example, the JSlider class uses a bound
property interface called the BoundedRangeModelapi
to define its model. At any time you like, you can replace the default
bound property of a component (such as the JSlider component instantiated
in the preceding code fragment) with a model of your own design
by calling a method named setModel().
Here's an example:
JSlider slider
= new JSlider();
BoundedRangeModel myModel = new DefaultBoundedRangeModel()
{
public void setValue(int n) {
System.out.println("SetValue:
"+ n);
super.setValue(n);
}
};
slider.setModel(myModel);
Different Models for
Different Components
By default, different kinds of components are equipped with different
kinds of models. For example, the default model that Swing supplies
for a JButton object is a GUI state model -- that is, an interface
that defines the visual status of a GUI control, such the current
state of a button. Similarly, the JList class is equipped with a
GUI state model that can specify which items are selected in a list.
More complex components, such as JTrees and JTables, are equipped
with more sophisticated default models application-data models --
that is, with interfaces that can manage more complex information,
such as the value of a cell in a table or the items displayed in
a tree. These data models provide a very powerful programming paradigm
for Swing programs that need a clean separation between their GUI
and their application data and logic.
Swing´s Pluggable
Look and Feel
Here´s one definition of PL&F: It´s the portion of
a Swing component's implementation that deals with the component's
appearance (or look), as distinguished from its event-handling mechanism
(its feel), which is delegated to a separate UI delegate. The currently
installed L&F module is what supplies this UI delegate.
The user of a Swing application can change UI delegates at runtime,
so it's possible for the user of a cleverly designed Swing application
to change the appearance and behavior (look and feel) of the application's
components while the program is running.
Complexity and the need to know
Although any Swing developer can learn to use PL&F, but mastering
it does require a firm grasp of some fairly complex topics. So if
you ever need (or want) to develop a custom look-and-feel, you'll
undoubtedly have to do some homework before you start writing code.
It is a challenge. But, as challenges go, it is a rewarding one.
Another point: Although Swing's PL&F feature is complex, its
complexity doesn't have much impact on most Swing developers because
most of them will never be called upon to use it. The PL&F mechanism
is designed to be used by a small subset of developers who have
a particular need to develop new look-and-feel implementations.
In most circumstances, other categories of developers will probably
find that it's enough to understand the capabilities of the PL&F
mechanism so they can make decisions on how they want to support
look-and-feels (such as deciding whether they want to lock an application
into using a single look-and-feel or whether they want to support
look-and-feel reconfigurations by the user). Swing's UIManager class
is the API that supports L&F management at this level.
The LookAndFeel Class
The Swing API defines an abstract LookAndFeelapi
class that completely characterizes a look and feel from the point
of view of the pluggable look and feel components. The LookAndFeel
class represents all the information needed
to create and implement a look-and-feel implementation, such as
its name, its description, a property that specifies whether it's
a native L&F -- and, finally, a hash table (commonly called
a defaults table in Swing) for storing default values for various
look-and-feel attributes, such as colors and fonts.
Every look-and-feel implementation defines an extension of the
LookAndFeel class that an application can use to provide Swing with
the necessary information to manage its L&Fs. For example, swing.plaf.motif.MotifLookAndFeel
is a subclass that can be used to manage a Motif L&F in an application.
The recommended practice is for components and applications to
access LookAndFeel objects indirectly, using the UIManager. Applications
should rarely, if ever, talk directly to an instance of the LookAndFeel
class. By accessing the class through the UI manager, an application
can keep track of which LookAndFeel classes are available, which
are installed, and which is currently the default. The UI manager
also manages access to the defaults table being used by the current
look-and-feel.
Default and custom L&Fs
When you load a program that makes use of Swing components, Swing's
default behavior is to initialize the Java look and feel that ships
with Swing. But any Swing program can set its own default by simply
calling a UIManager method named setLookAndFeel().
For example, the following code sample sets the Motif CDE (Common
Desk Environment) to be the default L&F:
UIManager.setLookAndFeel
("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
The UIManager also provides
a getLookAndFeel()
method for obtaining the current L&F. In addition, there are
UIManager methods for getting the current system look and feel,
for setting the current L&F to whatever platform a program is
running on, and for managing look-and-feel operations in many other
kinds of ways.
You can learn more about Swing´s PL&F capabilities by reading
the articles in the PLAF
Papers section of The Swing Connection. But we won´t go into
any more detail about PL&F in this article. Instead, we´ll move
right along to Part
3, where you´ll learn how to create and activate an applet using
Swing.
Part
3
|