IBM Skip to main content
Search for:   within 
      Search help  
     IBM home  |  Products & services  |  Support & downloads   |  My account

developerWorks > Java technology
developerWorks
Enhance the accessibility of your GUIs
code165 KBe-mail it!
Contents:
It's better to look good than to feel good
Overloading the Metal look and feel
Modifying the icons
Scaling the icons
A high-contrast look and feel
Using the new look and feel
Conclusion
Resources
About the author
Rate this article
Related content:
Coding for accessibility
Building accessible Web sites
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
Build a customizable cross-platform look and feel for visually impaired users

Level: Introductory

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
Default theme

Figure 2. High Contrast theme
High Contrast theme

Thus, customizing the colors and the fonts of the Metal look and feel is as easy as:

  1. 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)

  2. Overloading the getXXXFont() or getXXXColor() methods from the theme class so they return the fonts or colors needed in the new theme.

  3. 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
A 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
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
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

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.


code165 KBe-mail it!

What do you think of this document?
Killer! (5) Good stuff (4) So-so; not bad (3) Needs work (2) Lame! (1)

Comments?



developerWorks > Java technology
developerWorks
  About IBM  |  Privacy  |  Terms of use  |  Contact