![]() ![]() |
![]() |
![]() ![]() ![]() ![]() |
![]() |
A UIFactory object -- that is, an object of the UIFactory class -- generates all the UI objects for the pluggable-L&F (look and feel) components used in Swing. A UIFactory object also manages a set of properties that are shared by the UI objects it creates. Finally, it manages access to the resources used by UI classes, such as image files.
NOTE: Because of Swing's pluggable look-and feel architecture, every component can be associated with a single user interface, and each UI can be obtained from a different UI factory. For occasions when a more flexible UI-factory mechanism is needed, Swing also has a multiplexing UI factory class. This special kind of UI factory class can simultaneously and automatically create multiple user interfaces for different components from different UI factories. For more details, see the specification titled "The Multiplexing UI Factory."
Swing's pluggable-L&F architecture allows customization of components at many different levels. For example:
NOTE: For more information on the architecture of Swing's pluggable-L&F components, see the "Component Architecture" specification.
One of the most important features of Swing's L&F mechanism is that a developer can use Swing's pluggable-L&F components without having to understand how the pluggable L&F mechanism works. That's because all the complexity of the pluggable-L&F mechanism is wrapped inside Swing's basic component API. It is still possible to simply override a component's paint() method (to render your own look directly) or to install your own event-handlers (to handle your own feel).
Additionally, many developers want to know exactly how a program will look and feel when the user runs it and do not want it to be changed. For this reason, the architecture of Swing's pluggable-L&F components makes it easy for developers to lock in a specific look and feel that cannot be changed dynamically at runtime.
The Swing set's pluggable-L&F design is very different from the "peer" architecture currently used by the AWT. AWT's peer architecture was designed to delegate the look and feel of components to the native widget set of the user's computer platform. Furthermore, as much of the component's state as necessary was also duplicated in the native widget (an operation that presented many problems with consistency and synchronization). One of the most critical limitations of the peer architecture (a limitation that has been removed with the advent of pluggable-L&F) is that the look and feel of a components could not be easily or reliably extended. Additionally, the peer model did not allow a particular look and feel to be switched across platforms (it was fixed from platform to platform), much less switched at runtime.
In Swing, each UIFactory manages a collection of UI classes that map
to UI interfaces requested by a Swing component. For example, suppose your
application contained a UI class named foo.bar.MyButton
UI
class that mplemented the ButtonUI
interface and used a UIFactory
named ExampleFactory. If all those conditions existed, ExampleFactory could
return instances of button components in response to UIFactory.getUI()
method calls. The mapping of UI classes to UI interfaces is (currently)
stored in a properties file that is packaged with the specific UIFactory
subclass.
When a request is made for a new UI object (by invoking UIFactory.getUI()
),
the UIFactory dynamically loads the mapped UI class and then invokes its
createUI()
method. The createUI()
method is a
required method defined in each UI class. It is static, so implementations
aren't required to create separate UI objects (for the sake of memory conservation,
for example). The createUI()
method is not required to return
a unique UI object -- just an object that can be cast to the associated
UI interface as mapped by the UIFactory's properties file.
Each MVC-based component used in Swing has an associated UI interface.
UI classes can be added to a UIFactory via the installUI()
method and can be removed using the deinstallUI()
method. But
these are restricted-access methods that normally are used only by a UIFactory
builder. (Because components and factories are purposely isolated from each
other, it would be inappropriate for a component to modify the contents
of a factory).
Here's an example of how an MVC component can get a UI object from the default factory:
ComponentUI ui =
UIManager.getDefaultFactory().getUI
("Foo", "my.pkg.DefaultFooUI"));
The getUI()
method takes two parameters: a name and a default
implementation class. The name argument is a
name suitable for display by builders, such as "Button,""ScrollbarUI,"
or "Chuck's Widget." The default implementation class specifies
a class to use to instantiate the UI object if the UIFactory doesn't know
how to create a UI object for the requested widget.
A UIFactory can define standard default properties. These are used when an application displays something that uses the UIFactory's look and feel. The properties currently defined are:
A pluggable-L&F mechanism consists of more than class files; there
must be, at a minimum, a properties file for the UIFactory. There can also
be files for images, and other supporting files as well. In Swing, the UIFactory
base class has two methods for retrieving such resources. One is getResourceAsStream()
,
which is a generic access method for resource files. The other method is
getImage()
, which returns a loaded Image.
In Swing, each UIFactory subclass must implement three abstract methods, which normally just return constant strings:
getFactoryName()
: The name of current UIFactory. This
method used to differentiate the UIFactory currently being used from other
installed factories.getPropertiesFile()
: The relative path of the properties
file.getResourceDirectory()
: The relative path of the top-level
directory for resource files. Subdirectory paths are supported by including
them with the filename when accessing the resource file.
Here's an example:
public String getFactoryName() {
return "MyFactory";
}
public String getPropertiesFile() {
return "MyFactory.properties";
}
public String getResourceDirectory() {
return "resources";
}
The reason for requiring a UIFactory subclass that can contain only constant
strings is to facilitate the packaging of a pluggable look and feel. UIFactory
uses the new (1.1) JDK method Class.getResourceAsStream()
,
which is implemented by each class loader. This strategy allows all the
files associated with a pluggable look and feel to be separate from a JDK
installation, and allows them to be stored in and accessed from a JAR file.
Pluggable look and feels may therefore be signed and distributed independently
of JDK releases or Java applications.
The UIFactory class serves as the base class for all UIFactory implementations. (Each Pluggable Look and Feel must have a UIFactory subclass). It includes support for:
The UIManager class manages the list of installed UIFactory classes. It has methods to add, list, and remove UIFactory classes from a system list, and to set the default UIFactory. All of its methods are static, so there can be only one UIManager loaded in any Java VM.
Version 0.4. Last modified 09/04/97.
Copyright © 1995-97 Sun
Microsystems, Inc. All Rights Reserved.