|
|
Contents: |
|
|
|
Related content: |
|
|
|
Subscriptions: |
|
|
| Build a customizable cross-platform look and feel for
visually impaired users
Yannick
Saillet (mailto:ysaillet@de.ibm.com?cc=&subject=Enhance
the accessibility of your GUIs) Software Engineer, IBM 9 July
2003
One of the main characteristics of the
JFC/Swing framework is its ability to use pluggable look-and-feel
designs. The same application can be run with different look-and-feel
designs without requiring any modification. In this article, Software
Engineer Yannick Saillet explains the mechanism behind the Metal look
and feel -- one of the standard look and feel designs provided with the
J2SE platform -- and demonstrates how to modify it into a universal,
customizable look and feel to accommodate special user needs, such as
high contrast or large fonts for the visually
impaired.
Until the 1.4.2 release, J2SE included three pluggable look-and-feel
(PLAF) designs:
- Windows: Emulates the Windows 2000 operating system (because
of licensing restrictions, this PLAF can only be used under a Windows
platform)
- Motif: Emulates a Motif application
- Metal: Uses its own look and feel independent from any
existing operating system
J2SE 1.4.2 provides two additional look-and-feel designs, which John
Zukowski described in his Magic with Merlin column "J2SE 1.4.2 gets
two new look-and-feel designs" (see Resources).
The two new look-and-feel designs are:
- Windows XP: Emulates the Windows XP operating system (it can
only be used under a Windows platform)
- GTK+: Emulates a GTK application under Linux
It's better to look good than to
feel good For most people, an application's look and feel is
only a matter of preferences and aesthetics. But in some cases it is
necessary to customize the application's look and feel so that it uses
specific fonts, color schemes, or icons. Visually impaired users, for
example, often need a look and feel with a high contrast between text and
background, as well as large fonts and icons. The "IBM Java Accessibility
Checklist" (see Resources)
specifies that all user interface objects in an application must support
high contrast settings.
Earlier releases of the Java platform did not support color and font
preferences very well. Since J2SE 1.4 -- and especially with the
introduction of the new Windows XP and GTK look-and-feel designs in J2SE
1.4.2 -- users can now configure the desired look-and-feel designs. The
Windows look and feel tries to reuse the color and font schemes of the
underlying Windows platform, and the GTK look and feel enables Linux users
to define some scripts to customize the look and feel.
At first glance, the improvement of the "native" look-and-feel designs
seems to make the Metal look and feel useless. However, there are still
some cases where the Metal look and feel (or a customized version of it)
can be helpful. For instance:
- If you need a look and feel that runs under any platform and is
customizable even when used by an unsigned applet
- If you need more customization than the possibilities offered by the
other look-and-feel designs
- If you are using an earlier release of the Java platform for which
the latest improvements are not available
This article explains how you can modify the Metal look and feel to use
specific font and color schemes. You'll also learn how to modify the icons
used to draw widgets such as check boxes, radio buttons, trees, and file
dialogs.
I'll begin by explaining how the colors and the fonts used by the look
and feel can be overloaded. Then we'll review how the icons used by the
standard widgets can be modified. Finally, we'll walk through a complete
example of a new look and feel where you can define the settings for the
colors, fonts, and icon sizes in a simple text file. You can then use our
example to create your own high-contrast look and feel.
Overloading the Metal look and feel
-- modifying the colors and the fonts The
javax.swing.plaf.metal.MetalLookAndFeel class is the main
class of the Metal look and feel. The Java API documentation of this class
(see Resources)
shows that most of the methods defined in it are getters returning the
colors and fonts to draw the different widgets available in the Swing
framework. However, the return value of these getters is not directly
implemented in this class but is delegated to another class, which is
called a theme. The only purpose of the theme is to provide the
values of the colors and fonts to use.
The Metal look and feel uses a pluggable theme architecture. The look
and feel itself (javax.swing.plaf.metal.MetalLookAndFeel )
defines what the widgets look like and how they should react to user
interactions, while the theme defines which colors and fonts you should
use when painting the widget. You can define a new theme by creating a new
class that inherits from
javax.swing.plaf.metal.MetalTheme.
Figures 1 and 2 show two screenshots from the SwingSet demos that come
with the JSDK. They demonstrate how different themes can change the look
of an application, even when the same look and feel is used.
Figure 1. Default theme
Figure 2. High Contrast theme
Thus, customizing the colors and the fonts of the Metal look and feel
is as easy as:
- Creating a new class that extends
javax.swing.plaf.metal.MetalTheme or its default
implementation javax.swing.plaf.metal.DefaultMetalTheme
(see the reference to the Java API documentation in the Resources
section)
- Overloading the
getXXXFont() or
getXXXColor() methods from the theme class so they return
the fonts or colors needed in the new theme.
- Setting the new theme in the Metal look and feel by invoking the
MetalLookAndFeel.setCurrentTheme(theme) static method.
The Java API documentation (see Resources)
for javax.swing.plaf.metal.MetalTheme shows that you can
overload about 50 different methods to define, on a fine-grained level,
which colors and fonts have to be used. Unfortunately, most of these
methods are not documented, making it a painful task to test each method
to check the impact it has on the user interface.
Fortunately, you usually don't need to overload all of the available
methods to get an acceptable result -- if
javax.swing.plaf.metal.MetalTheme provides numerous methods,
its default implementation
javax.swing.plaf.metal.DefaultMetalTheme implements most of
them in a consistent way so that they all return the result of one of the
following methods:
getBlack()
getWhite()
getPrimary1()
getPrimary2()
getPrimary3()
getSecondary1()
getSecondary2()
getSecondary3()
getControlTextFont()
getMenuTextFont()
getSubTextFont()
getSystemTextFont()
getUserTextFont()
getWindowTitleFont()
Thus, subclassing javax.swing.plaf.metal.DefaultMetalTheme
and overloading these eight colors and six fonts is usually sufficient to
get a consistent new theme.
Instead of hardcoding these methods (as is done in the themes provided
by the Java platform), it's a good idea to implement a generic theme that
returns colors and fonts specified in an external resource file. This way,
we can easily define a new theme -- we only need to edit a few values with
any text editor.
Modifying the icons In
some cases, it may be necessary to modify the icons and graphical
resources used by the look and feel as well. For example, you may want to
modify the icons used by the check boxes and radio buttons to paint their
status, or you may want to use other icons to paint the folders and nodes
of a tree component.
Modifying the icons, for example, is necessary if you want a look and
feel with large fonts. The size of the icons used in check boxes and radio
buttons should be adapted to the size of their font. Check boxes with
large fonts won't help a visually impaired user if he can't tell whether
the check box is checked or unchecked, because the size of its icon has
remained unchanged.
Figure 3 shows an example of a high contrast and large font theme in
which the size of the icons are unchanged. You can see the disproportion
between the font size and the size of the icons.
Figure 3. A high contrast and large font theme
without adjusted icon size
Unfortunately, icons cannot be modified in a theme. Therefore, we have
to use another technique if we want to overload the icons used by the
Metal look and feel.
The Metal look and feel stores the list of the graphical resources to
be used (colors, fonts, and images) in a
javax.swing.UIDefaults object, which is basically a kind of
hashtable. Each image required by the different widgets is stored by the
look and feel under a specific key in this table, so that it can be easily
retrieved. That means also that if you know under which key a specific
image is stored, you can replace it by storing another image under the
same key.
Let's look at how the Metal look and feel initializes the table
containing the graphical resources.
When the look and feel is created, it first instantiates an empty
UIDefaults object that is filled by the following
methods:
initClassDefaults(UIDefaults)
initComponentDefaults(UIDefaults)
initSystemColorDefaults(UIDefaults)
Each of these methods is consecutively invoked by the look and feel
itself. They consecutively store graphical resources (either colors,
fonts, or images) in the UIDefaults tables under unique keys.
For more detail, see the API documentation (see Resources)
of the javax.swing.plaf.MetalLookAndFeel class. The
initialization of the images is done in
initComponentDefaults(UIDefaults ). Overloading this method
allows you to replace any standard image used in the look and feel.
Unfortunately, the keys under which the icons are stored are not
documented, but the source code of the
javax.swing.plaf.MetalLookAndFeel class provides this
information. It reveals how the icons are built for the Metal look and
feel. Table 1 shows a list of the existing keys that refer to icons in the
Metal look and feel:
Table 1. Keys that refer to icons in the Metal look and feel
CheckBox.icon |
InternalFrame .closeIcon |
RadioButton.icon |
InternalFrame.maximizeIcon |
InternalFrame.icon |
InternalFrame.iconifyIcon |
InternalFrame.iconifyIcon |
InternalFrame.minimizeIcon |
FileView.directoryIcon |
Menu.checkIcon |
FileView.fileIcon |
Menu.arrowIcon |
FileView.computerIcon |
MenuItem.checkIcon |
FileView.hardDriveIcon |
MenuItem.arrowIcon |
FileView.floppyDriveIcon |
CheckBoxMenuItem.checkIcon |
FileChooser.detailsViewIcon |
CheckBoxMenuItem.arrowIcon |
FileChooser.homeFolderIcon |
RadioButtonMenuItem.checkIcon |
FileChooser.listViewIcon |
RadioButtonMenuItem.arrowIcon |
FileChooser.newFolderIcon |
Tree.openIcon |
FileChooser.upFolderIcon |
Tree.closedIcon |
Slider.horizontalThumbIcon |
Tree.leafIcon |
Slider.verticalThumbIcon |
Tree.expandedIcon |
InternalFrame.icon |
Tree.collapsedIcon |
InternalFrame.paletteCloseIcon |
Scaling the icons In
contrast to the other look-and-feel designs delivered with the Java
platform, the Metal look and feel does not use GIF files to paint its
icons. It creates them dynamically through a factory class called
javax.swing.plaf.metal.MetalIconFactory . For each of the keys
listed in Table 1, it provides a corresponding getXXXIcon()
method that paints a vectorial icon.
Vectorial icons created by a factory have the advantage that they can
use the colors defined by the current theme instead of predefined colors.
Because the icons are vectorial, it is usually easy to modify their scale
without sacrificing quality. Unfortunately, except for four icons, none of
the methods in MetalIconFactory accepts a parameter that
defines the size of the icon. Therefore, the only way to define the size
of icons is to build a completely new icon factory.
Fortunately, there is a workaround to this problem. You can create a
class that implements the javax.swing.Icon interface, takes
an existing icon and scale factor as its argument in its constructor, and
uses the java.awt.Graphics2D API to paint a rescaled version
of the icon as a bitmap image (see Listing 1). Of course, it means a loss
of quality when an icon is enlarged. However, this is much easier to
implement than building a new icon factory. Furthermore, the quality is
still acceptable for simple icons such as check boxes and radio
buttons. Listing 1. An icon magnifier
/** A class to create a magnified version of an existing icon */
protected class MagnifiedIcon implements Icon {
private Icon icon ;
private double factor ;
public MagnifiedIcon(Icon icon, double factor) {
this.icon = icon ;
this.factor = factor ;
}
public int getIconWidth() {
return (int)(icon.getIconWidth()*factor) ;}
public int getIconHeight() {
return (int)(icon.getIconHeight()*factor) ;}
public void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2d = (Graphics2D)g.create() ;
g2d.translate(x,y);
g2d.scale(factor, factor);
icon.paintIcon(c,g2d,0,0);
g2d.dispose();
}
}
|
A customizable, high-contrast look
and feel Listing 2 shows the source code for the generic look and
feel that is based on the Metal look and feel and a color scheme that was
created to provide a customizable, operating system-independent,
high-contrast look and feel. (Download the source code from Resources.)
Lines 9 through 16 load the external resource file that defines the
properties of the look and feel. They install a customized theme that uses
this resource file to define the colors and the fonts.
Lines 18 through 20 overwrite standard methods of
MetalLookAndFeel so that the name, description, and ID of the
look and feel is also externalized in the resource file.
Lines 22 through 53 modify the UIDefaults of the look and feel to
magnify the standard icons by a factor defined in the external resource
file. The magnification itself is made by the MagnifiedIcon
inner class (lines 95 through 113).
Lines 56 through 92 comprise the implementation of the customized
theme. They first read in the resource file the name and size of the font
to be used (lines 64 through 70). Then they overwrite the getter methods
of DefaultMetalTheme so that the font and colors defined in
the external resource file are used.
Listing 3 shows the external resource files for the Black on White Look
and Feel, Large Fonts. The font size for this look and feel is set to 30
(line 5), the icons are scaled to 250 percent of their original size (line
3), and the basic colors are set to black and white (lines 6 through
15). Listing 3. HighContrastLAF.properties: Black on
white
1 name = High Contrast Look And Feel
2. description = Black on white, large fonts
3. iconMagnificationFactor = 2.5
4. fontName = Dialog
5. fontSize = 30
6. backgroundColor = FFFFFF
7. foregroundColor = 000000
8. primaryColor1 = 000000
9. primaryColor2 = FFFFFF
10. primaryColor3 = FFFFFF
11. secondaryColor1 = 000000
12. secondaryColor2 = C0C0C0
13. secondaryColor3 = FFFFFF
14. selectionForeground = FFFFFF
15. selectionBackground = 000000
|
Figure 4 shows a screenshot of this look and feel.
Figure 4. Black text on white
background
In the same way, you can create a high-contrast look and feel with
white text on black background and normal font size just by providing
another resource file as shown in Listing 4. Listing
4. HighContrastLAF.properties: White on black
1. name = High Contrast Look And Feel
2. description = White on black
3. iconMagnificationFactor = 1
4. fontName = Dialog
5. fontSize = 14
6. backgroundColor = 000000
7. foregroundColor = FFFFFF
8. primaryColor1 = FFFFFF
9. primaryColor2 = 000000
10. primaryColor3 = 000000
11. secondaryColor1 = FFFFFF
12. secondaryColor2 = 808080
13. secondaryColor3 = 000000
14. selectionForeground = 000000
15. selectionBackground = FFFFFF
|
Figure 5 shows the result of Listing 4.
Figure 5. White text on black
background
Using the new look and feel in your
Java application You can use the newly created look and feel
in any Swing application by invoking the following line in the
main method before the first widget is created:
UIManager.setLookAndFeel("HighContrastLAF");
|
Ideally, your product provides a dialog or preference page that lets
users select the look and feel of their choice. But if you are not ready
to invest so much effort, a much easier solution is to use the system
properties to allow users to specify the look and feel in the command line
that starts the program, as shown in Listing 5. Listing 5. Initializing the LAF from a system
property
String plaf = System.getProperty("plafName") ;
if (plaf!=null) try {
UIManager.setLookAndFeel(plaf);
} catch (Exception e) { ("Error loading PLAF "+plaf+":"+e);}
|
Users can then select a specific look and feel by using the following
syntax in the command line when they start the application:
java -DplafName=HighContrastLAF -classpath CLASSPATH MAINCLASS ARGUMENTS
|
Conclusion In this
article, we've shown how easy it is to customize the cross-platform Metal
look and feel. As we've discussed, this can be achieved by subclassing the
MetalLookAndFeel and DefaultMetalThemes classes.
We have also shown how you can easily enlarge icons by using scaled icons.
You can use the source code from this article as is or modify it in your
projects to provide more customization possibilities for visually impaired
users.
Resources
- Download the complete
source code for this article.
- John Zukowski's Magic with Merlin column touched on the two
new
look-and-feel designs in J2SE 1.4.2 (developerWorks, May
2003).
- See the IBM
Java Accessibility Checklist that Java applications should fulfill
to comply with section 508 of the
U.S. Rehabilitations Act and related accessibility
standards.
- Visit the JFC home
page to learn about JFC/Swing.
- The JFC home page contains a series of papers related to the
creation of pluggable
look-and-feel designs.
- This Web site provides a
collection of Swing look-and-feel designs.
- See the Java API
documentation for the API of the different classes referenced in
this article.
- To learn more about Java accessibility features and creating
accessible Java-based software, see the "IBM
Guidelines for Writing Accessible Applications Using 100% Pure
Java."
- Kim Stephens, Webmaster of the IBM Worldwide Accessibility Center
Web site, wrote a three-part tutorial series on the features, functions,
and controls that you must design into Web pages to make them accessible
to people with disabilities (developerWorks December 2000-May
2001):
- Part
1 touches on the concepts.
- Part
2 explores images and animation.
- Part
3 shows techniques for creating and testing alternative content
for multimedia, scripts, applets, and plug-ins when creating
accessible Web pages.
- Dr. Barry Feigenbaum, a Senior IT Specialist at the IBM Worldwide
Accessibility Center, has written several books and articles related to
accessibility, including "Coding
for accessibility" (developerWorks, October 2002).
- Find hundreds more Java technology resources on the developerWorks
Java technology zone.
About the
author Yannick Saillet joined IBM Germany as a software
developer in 1998. He first worked for IBM Learning Services as a
software engineer in several distributed learning projects. He
joined the IBM Boeblingen Laboratory in 2000 where he has been
active in the development of the DB2 Intelligent Miner products. You
can contact Yannick at ysaillet@de.ibm.com. |
|