11.13 Themes and the Metal Look-and-Feel

The default platform-independent look-and-feel for Swing applications is known as the Metal look-and-feel. One of the powerful but little-known features of Metal is that the fonts and colors it uses are easily customizable. All you have to do is pass a MetalTheme object to the static setCurrentTheme( ) method of MetalLookAndFeel. (These classes are defined in the infrequently used javax.swing.plaf.metal package.)

The MetalTheme class is abstract, so, in practice, you work with DefaultMetalTheme. This class has six methods that return the basic theme colors (really three shades each of a primary and a secondary color) and four methods that return the basic theme fonts. To define a new theme, all you have to do is subclass DefaultMetalTheme and override these methods to return the fonts and colors you want. (If you want more customizability than this, you have to subclass MetalTheme directly.)

Example 11-28 is a listing of ThemeManager.java. This example includes a subclass of DefaultMetalTheme, but defines it as an inner class of ThemeManager. The ThemeManager class provides the ability to read theme definitions (i.e., color and font specifications) from a GUIResourceBundle and defines methods for reading the name of a default theme and a list of names of all available themes from the bundle. Finally, ThemeManager can return a JMenu component that displays a list of available themes to the user and switches the current theme based on the user's selection.

ThemeManager also demonstrates a feature unrelated to DefaultMetalTheme: it includes the ability to tell Swing whether it should provide audio feedback for all, some, or none of the user actions for which Swing is capable of playing sounds. It does this by setting an undocumented property[4] with the UIManager.put( ) method.

[4] The properties are not documented within the javadoc API, but you can find out more by searching the web for the string "AuditoryCues.playList".

ThemeManager, and the JMenu component it creates, were used in the WebBrowser class of Example 11-21. Before you examine the ThemeManager code, take a look at the following lines excerpted from the WebBrowserResources.properties file, which define the set of available themes for the web browser:

# This property defines the property names of all available themes. themelist: theme.metal theme.rose, theme.lime, theme.primary, theme.bigfont # This property defines the name of the default property defaultTheme: theme.metal # This theme only has a name.  All font and color values are unchanged from # the default Metal theme theme.metal.name: Default Metal # This theme uses shades of red/pink theme.rose.name: Rose theme.rose.primary: #905050 theme.rose.secondary: #906050 theme.rose.sounds: all # This theme uses lime green colors theme.lime.name: Lime theme.lime.primary: #509050 theme.lime.secondary: #506060 theme.lime.sounds: none # This theme uses bright primary colors theme.primary.name: Primary Colors theme.primary.primary: #202090 theme.primary.secondary: #209020 theme.primary.sounds: default # This theme uses big fonts and the default colors theme.bigfont.name: Big Fonts theme.bigfont.controlFont: sansserif-bold-18 theme.bigfont.menuFont: sansserif-bold-18 theme.bigfont.smallFont: sansserif-plain-14 theme.bigfont.systemFont: sansserif-plain-14 theme.bigfont.userFont: sansserif-plain-14 theme.bigfont.titleFont: sansserif-bold-18

With these theme definitions, you should have no trouble understanding the resource-parsing code of ThemeManager. getThemeMenu( ) creates a JMenu populated by JRadioButtonMenuItem objects, rather than JMenuItem or Action objects, as we've seen earlier in this chapter. This emphasizes the fact that only one theme can be selected at a time. When the theme is changed, the setTheme( ) method uses a SwingUtilities method to propagate the change to all components within the frame. Finally, note that the Theme inner class doesn't use Font and Color objects, but uses FontUIResource and ColorUIResource objects instead. These classes are part of the javax.swing.plaf package and are trivial subclasses of Font and Color that implement the UIResource marker interface. This interface allows components to distinguish between property values assigned by the look-and-feel, which all implement UIResource, and property values assigned by the application. Based on this distinction, application settings can override look-and-feel settings, even when the look-and-feel (or theme) changes while the application is running.

Example 11-28. ThemeManager.java
package je3.gui; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.plaf.*; import javax.swing.plaf.metal.MetalLookAndFeel; import javax.swing.plaf.metal.DefaultMetalTheme; /**  * This class reads theme descriptions from a GUIResourceBundle and uses them  * to specify colors and fonts for the Metal look-and-feel.  It also   * demonstrates an undocumented feature for turning Swing notification sounds  * on and off.  **/ public class ThemeManager {     JFrame frame;                  // The frame which themes are applied to     GUIResourceBundle resources;   // Properties describing the themes     /**       * Build a ThemeManager for the frame and resource bundle.  If there      * is a default theme specified, apply it to the frame      **/     public ThemeManager(JFrame frame, GUIResourceBundle resources) {         this.frame = frame;         this.resources = resources;         String defaultName = getDefaultThemeName( );         if (defaultName != null) setTheme(defaultName);     }     /** Look up the named theme, and apply it to the frame */     public void setTheme(String themeName) {         // Look up the theme in the resource bundle         Theme theme = new Theme(resources, themeName);         // Make it the current theme         MetalLookAndFeel.setCurrentTheme(theme);         // Reapply the Metal look-and-feel to install new theme         try { UIManager.setLookAndFeel(new MetalLookAndFeel( )); }         catch(UnsupportedLookAndFeelException e) {  }         // If the theme has an audio playlist, then set it         if (theme.playlist != null)             UIManager.put("AuditoryCues.playList", theme.playlist);         // Propagate the new l&f across the entire component tree of the frame         SwingUtilities.updateComponentTreeUI(frame);     }     /** Get the "display name" or label of the named theme */     public String getDisplayName(String themeName) {         return resources.getString(themeName + ".name", null);     }     /** Get the name of the default theme, or null */     public String getDefaultThemeName( ) {         return resources.getString("defaultTheme", null);     }     /**      * Get the list of all known theme names.  The returned values are      * theme property names, not theme display names.      **/     public String[  ] getAllThemeNames( ) {         java.util.List names = resources.getStringList("themelist");         return (String[  ]) names.toArray(new String[names.size( )]);     }     /**      * Get a JMenu that lists all known themes by display name and      * installs any selected theme.      **/     public JMenu getThemeMenu( ) {         String[  ] names = getAllThemeNames( );         String defaultName = getDefaultThemeName( );         JMenu menu = new JMenu("Themes");         ButtonGroup buttongroup = new ButtonGroup( );         for(int i = 0; i < names.length; i++) {             final String themeName = names[i];             String displayName = getDisplayName(themeName);             JMenuItem item = menu.add(new JRadioButtonMenuItem(displayName));             buttongroup.add(item);             if (themeName.equals(defaultName)) item.setSelected(true);             item.addActionListener(new ActionListener( ) {                     public void actionPerformed(ActionEvent event) {                         setTheme(themeName);                     }                 });         }         return menu;     }     /**      * This class extends the DefaultMetalTheme class to return Color and      * Font values read from a GUIResourceBundle      **/     public static class Theme extends DefaultMetalTheme {         // These fields are the values returned by this Theme         String displayName;         FontUIResource controlFont, menuFont, smallFont;         FontUIResource systemFont, userFont, titleFont;         ColorUIResource primary1, primary2, primary3;         ColorUIResource secondary1, secondary2, secondary3;         Object playlist;  // auditory cues         /**          * This constructor reads all the values it needs from the          * GUIResourceBundle.  It uses intelligent defaults if properties          * are not specified.          **/         public Theme(GUIResourceBundle resources, String name) {             // Use this theme object to get default font values from             DefaultMetalTheme defaultTheme = new DefaultMetalTheme( );             // Look up the display name of the theme             displayName = resources.getString(name + ".name", null);             // Look up the fonts for the theme             Font control = resources.getFont(name + ".controlFont", null);             Font menu = resources.getFont(name + ".menuFont", null);             Font small = resources.getFont(name + ".smallFont", null);             Font system = resources.getFont(name + ".systemFont", null);             Font user = resources.getFont(name + ".userFont", null);             Font title = resources.getFont(name + ".titleFont", null);             // Convert fonts to FontUIResource, or get defaults             if (control != null) controlFont = new FontUIResource(control);             else controlFont = defaultTheme.getControlTextFont( );             if (menu != null) menuFont = new FontUIResource(menu);             else menuFont = defaultTheme.getMenuTextFont( );             if (small != null) smallFont = new FontUIResource(small);             else smallFont = defaultTheme.getSubTextFont( );             if (system != null) systemFont = new FontUIResource(system);             else systemFont = defaultTheme.getSystemTextFont( );             if (user != null) userFont = new FontUIResource(user);             else userFont = defaultTheme.getUserTextFont( );             if (title != null) titleFont = new FontUIResource(title);             else titleFont = defaultTheme.getWindowTitleFont( );             // Look up primary and secondary colors             Color primary = resources.getColor(name + ".primary", null);             Color secondary = resources.getColor(name + ".secondary", null);             // Derive all six colors from these two, using defaults if needed             if (primary != null) primary1 = new ColorUIResource(primary);             else primary1 = new ColorUIResource(102, 102, 153);             primary2 = new ColorUIResource(primary1.brighter( ));             primary3 = new ColorUIResource(primary2.brighter( ));             if (secondary != null) secondary1 = new ColorUIResource(secondary);             else secondary1 = new ColorUIResource(102, 102, 102);             secondary2 = new ColorUIResource(secondary1.brighter( ));             secondary3 = new ColorUIResource(secondary2.brighter( ));             // Look up what type of sound is desired.  This property should             // be one of the strings "all", "none", or "default".  These map to             // undocumented UIManager properties.  playlist is an array of             // strings, but we keep it as an opaque object.             String sounds = resources.getString(name + ".sounds", "");             if (sounds.equals("all"))                 playlist = UIManager.get("AuditoryCues.allAuditoryCues");             else if (sounds.equals("none"))                 playlist = UIManager.get("AuditoryCues.noAuditoryCues");             else if (sounds.equals("default"))                 playlist = UIManager.get("AuditoryCues.defaultCueList");         }         // These methods override DefaultMetalTheme and return the property         // values we looked up and computed for this theme         public String getName( ) { return displayName; }         public FontUIResource getControlTextFont( ) { return controlFont;}         public FontUIResource getSystemTextFont( ) { return systemFont;}         public FontUIResource getUserTextFont( ) { return userFont;}         public FontUIResource getMenuTextFont( ) { return menuFont;}         public FontUIResource getWindowTitleFont( ) { return titleFont;}         public FontUIResource getSubTextFont( ) { return smallFont;}         protected ColorUIResource getPrimary1( ) { return primary1; }          protected ColorUIResource getPrimary2( ) { return primary2; }         protected ColorUIResource getPrimary3( ) { return primary3; }         protected ColorUIResource getSecondary1( ) { return secondary1; }         protected ColorUIResource getSecondary2( ) { return secondary2; }         protected ColorUIResource getSecondary3( ) { return secondary3; }     } }


Java Examples in a Nutshell
Java Examples in a Nutshell, 3rd Edition
ISBN: 0596006209
EAN: 2147483647
Year: 2003
Pages: 285

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net