Pluggable Look-and-Feel

A program that uses Java's Abstract Window Toolkit GUI components (package java.awt) takes on the look-and-feel of the platform on which the program executes. A Java application running on a Macintosh looks like other applications running on a Macintosh. A Java application running on Microsoft Windows looks like other applications running on Microsoft Windows. A Java application running on a UNIX platform looks like other applications running on that UNIX platform. This is sometimes desirable, because it allows users of the application on each platform to use GUI components with which they are already familiar. However, it also introduces interesting portability issues.

Portability Tip 22.1

GUI components look different on different platforms and may require different amounts of space to display. This could change their layout and alignments.

Portability Tip 22.2

GUI components on different platforms have different default functionality (e.g., some platforms allow a button with the focus to be "pressed" with the space bar, and some do not).

Swing's lightweight GUI components eliminate many of these issues by providing uniform functionality across platforms and by defining a uniform cross-platform look-and-feel (known as the metal look-and-feel). Swing also provides the flexibility to customize the look-and-feel to appear as a Microsoft Windows-style look-and-feel (on Window systems), a Motif-style (UNIX) look-and-feel (across all platforms) or a Macintosh look-and-feel (Mac systems).

The application in Fig. 22.9 and Fig. 22.10 demonstrates how to change the look-and-feel of a Swing GUI. The application creates several GUI components, so you can see the change in the look-and-feel of several GUI components at the same time. The first output window shows the standard metal look-and-feel, the second shows the Motif look-and-feel, and the third shows the Windows look-and-feel.

Figure 22.9. Look-and-feel of a Swing-based GUI.

(This item is displayed on pages 1023 - 1025 in the print version)

1 // Fig. 22.9: LookAndFeelFrame.java 2 // Changing the look and feel. 3 import java.awt.GridLayout; 4 import java.awt.BorderLayout; 5 import java.awt.event.ItemListener; 6 import java.awt.event.ItemEvent; 7 import javax.swing.JFrame; 8 import javax.swing.UIManager; 9 import javax.swing.JRadioButton; 10 import javax.swing.ButtonGroup; 11 import javax.swing.JButton; 12 import javax.swing.JLabel; 13 import javax.swing.JComboBox; 14 import javax.swing.JPanel; 15 import javax.swing.SwingConstants; 16 import javax.swing.SwingUtilities; 17 18 public class LookAndFeelFrame extends JFrame 19 { 20 // string names of look and feels 21 private final String strings[] = { "Metal", "Motif", "Windows" }; 22 private UIManager.LookAndFeelInfo looks[]; // look and feels 23 private JRadioButton radio[]; // radiobuttons to select look and feel 24 private ButtonGroup group; // group for radiobuttons 25 private JButton button; // displays look of button 26 private JLabel label; // displays look of label 27 private JComboBox comboBox; // displays look of combo box 28 29 // set up GUI 30 public LookAndFeelFrame() 31 { 32 super( "Look and Feel Demo" ); 33 34 JPanel northPanel = new JPanel(); // create north panel 35 northPanel.setLayout( new GridLayout( 3, 1, 0, 5 ) ); 36 37 label = new JLabel( "This is a Metal look-and-feel", 38 SwingConstants.CENTER ); // create label 39 northPanel.add( label ); // add label to panel 40 41 button = new JButton( "JButton" ); // create button 42 northPanel.add( button ); // add button to panel 43 44 comboBox = new JComboBox( strings ); // create combobox 45 northPanel.add( comboBox ); // add combobox to panel 46 47 // create array for radio buttons 48 radio = new JRadioButton[ strings.length ]; 49 50 JPanel southPanel = new JPanel(); // create south panel 51 southPanel.setLayout( new GridLayout( 1, radio.length ) ); 52 53 group = new ButtonGroup(); // button group for look and feels 54 ItemHandler handler = new ItemHandler(); // look and feel handler 55 56 for ( int count = 0; count < radio.length; count++ ) 57 { 58 radio[ count ] = new JRadioButton( strings[ count ] ); 59 radio[ count ].addItemListener( handler ); // add handler 60 group.add( radio[ count ] ); // add radiobutton to group 61 southPanel.add( radio[ count ] ); // add radiobutton to panel 62 } // end for 63 64 add( northPanel, BorderLayout.NORTH ); // add north panel 65 add( southPanel, BorderLayout.SOUTH ); // add south panel 66 67 // get installed look-and-feel information 68 looks = UIManager.getInstalledLookAndFeels(); 69 radio[ 0 ].setSelected( true ); // set default selection 70 } // end LookAndFeelFrame constructor 71 72 // use UIManager to change look-and-feel of GUI 73 private void changeTheLookAndFeel( int value ) 74 { 75 try // change look and feel 76 { 77 // set look and feel for this application 78 UIManager.setLookAndFeel( looks[ value ].getClassName() ); 79 80 // update components in this application 81 SwingUtilities.updateComponentTreeUI( this ); 82 } // end try 83 catch ( Exception exception ) 84 { 85 exception.printStackTrace(); 86 } // end catch 87 } // end method changeTheLookAndFeel 88 89 // private inner class to handle radio button events 90 private class ItemHandler implements ItemListener 91 { 92 // process user's look-and-feel selection 93 public void itemStateChanged( ItemEvent event ) 94 { 95 for ( int count = 0; count < radio.length; count++ ) 96 { 97 if ( radio[ count ].isSelected() ) 98 { 99 label.setText( String.format( "This is a %s look-and-feel", 100 strings[ count ] ) ); 101 comboBox.setSelectedIndex( count ); // set combobox index 102 changeTheLookAndFeel( count ); // change look and feel 103 } // end if 104 } // end for 105 } // end method itemStateChanged 106 } // end private inner class ItemHandler 107 } // end class LookAndFeelFrame

Figure 22.10. Test class for LookAndFeelFrame.

(This item is displayed on page 1026 in the print version)

1 // Fig. 22.10: LookAndFeelDemo.java 2 // Changing the look and feel. 3 import javax.swing.JFrame; 4 5 public class LookAndFeelDemo 6 { 7 public static void main( String args[] ) 8 { 9 LookAndFeelFrame lookAndFeelFrame = new LookAndFeelFrame(); 10 lookAndFeelFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 11 lookAndFeelFrame.setSize( 300, 200 ); // set frame size 12 lookAndFeelFrame.setVisible( true ); // display frame 13 } // end main 14 } // end class LookAndFeelDemo  

All the GUI components and event handling in this example have been covered before, so we concentrate on the mechanism for changing the look-and-feel in this example. Class UIManager (package javax.swing) contains nested class LookAndFeelInfo (a public static class) that maintains information about a look-and-feel. Line 22 declares an array of type UIManager.LookAndFeelInfo (note the syntax used to identify the inner class LookAndFeelInfo). Line 68 uses UIManager static method getInstalledLookAnd-Feels to get the array of UIManager.LookAndFeelInfo objects that describe each look-and-feel available on your system.

Performance Tip 22.1

Each look-and-feel is represented by a Java class. UIManager method getInstalledLookAnd-Feels does not load each class. Rather, it provides the names of the available look-and-feel classes so that a choice can be made (presumably once at program start-up). This reduces the overhead of having to load all the look-and-feel classes even if the program will not use some of them.

Our utility method changeTheLookAndFeel (lines 7387) is called by the event handler for the JRadioButtons at the bottom of the user interface. The event handler (declared in private inner class ItemHandler at lines 90106) passes an integer representing the element in array looks that should be used to change the look-and-feel. Line 78 invokes static method setLookAndFeel of UIManager to change the look-and-feel. Method getClassName of class UIManager.LookAndFeelInfo determines the name of the look-and-feel class that corresponds to the UIManager.LookAndFeelInfo object. If the look-and-feel class is not already loaded, it will be loaded as part of the call to setLookAndFeel. Line 81 invokes static method updateComponentTreeUI of class SwingUtilities (package javax.swing) to change the look-and-feel of every GUI component attached to its argument (this instance of our application class LookAndFeelDemo) to the new look-and-feel.

Категории