Pluggable Look-and-Feel

We mentioned before that Swing’s peerless components can easily change their appearance, like master spies or thespians. Generally, different kinds of components have appearances that are similar in some way. For example, they probably use the same font and the same basic color scheme. The collection of appearances for different components is called a look-and-feel (L&F).

Part of the job of designing a GUI for an operating system is designing the L&F. MacOS, therefore, has its own distinctive L&F, as does Windows. Java 2 offers not one, not two, but three different L&F schemes for Swing components. If you’re adept at graphic design, you can write your own L&F schemes and easily convince Swing to use them. This chameleon-like ability to change appearance is called pluggable look-and-feel , sometimes abbreviated PLAF.

Seeing is believing. Here’s an example that creates a handful of Swing components. Menu items allow you to change the L&F dynamically, as the application is running:

//file: QuickChange.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
 
public class QuickChange extends JFrame {
  
  public QuickChange( ) {
    super("QuickChange v1.0");
    createUI( );
    setVisible(true);
  }
 
  protected void createUI( ) {
    setSize(300, 200);
    setLocation(200, 200);

    // create a simple File menu
    JMenu file = new JMenu("File", true);
    JMenuItem quit = new JMenuItem("Quit");
    file.add(quit);
    quit.addActionListener(new ActionListener( ) {
      public void actionPerformed(ActionEvent e) { System.exit(0); }
    });
    
    // create the Look & Feel menu
    JMenu lnf = new JMenu("Look & Feel", true);
    ButtonGroup buttonGroup = new ButtonGroup( );
    final UIManager.LookAndFeelInfo[] info =
        UIManager.getInstalledLookAndFeels( );
    for (int i = 0; i < info.length; i++) {
      JRadioButtonMenuItem item = new
          JRadioButtonMenuItem(info[i].getName( ), i == 0);
      final String className = info[i].getClassName( );
      item.addActionListener(new ActionListener( ) {
        public void actionPerformed(ActionEvent ae) {
          try { UIManager.setLookAndFeel(className); }
          catch (Exception e) { System.out.println(e); }
          SwingUtilities.updateComponentTreeUI(QuickChange.this);
        }
      });
      buttonGroup.add(item);
      lnf.add(item);
    }

    // add the menu bar
    JMenuBar mb = new JMenuBar( );
    mb.add(file);
    mb.add(lnf);
    setJMenuBar(mb);

    // add some components
    JPanel jp = new JPanel( );
    jp.add(new JCheckBox("JCheckBox"));
    String[] names =
      new String[] { "Tosca", "Cavaradossi", "Scarpia",
                     "Angelotti", "Spoletta", "Sciarrone",
                     "Carceriere", "Il sagrestano", "Un pastore" };
    jp.add(new JComboBox(names));
    jp.add(new JButton("JButton"));
    jp.add(new JLabel("JLabel"));
    jp.add(new JTextField("JTextField"));
    JPanel main = new JPanel(new GridLayout(1, 2));
    main.add(jp);
    main.add(new JScrollPane(new JList(names)));
    setContentPane(main);
  }

  public static void main(String[] args) {
    JFrame f = new QuickChange( );
    f.addWindowListener(new WindowAdapter( ) {
      public void windowClosing(WindowEvent e) { System.exit(0); }
    });
    f.setVisible(true);
  }
}

The interesting part of this application is creating a menu of the available L& Fs. First, we ask a class called UIManager to tell us all about the available L&Fs on our computer:

final UIManager.LookAndFeelInfo[] info =
        UIManager.getInstalledLookAndFeels( );

Information about L&Fs is returned as instances of UIManager.LookAndFeelInfo. Despite the long name, there’s not much to this class—it just associates a name, like “Metal,” and the name of the class that implements the L&F, like javax.swing.plaf.metal.MetalLookAndFeel. In the QuickChange example, we create a menu item from each L&F name. If the menu item is selected, we tell the UIManager to use the selected L&F class. Then, to make sure all the components are redrawn with the new L&F, we call a static method in the SwingUtilities class called updateComponentTreeUI( ) .

The regular SDK includes three L&Fs, one that resembles Windows, one that resembles Motif, and an entirely new L&F called Metal. Metal is used by default; you’ve been staring at it through all the examples in this chapter and the last chapter.

If you’re running Swing on MacOS, there’s a MacOS L&F you can install and use. It does not, however, run on any other platforms.

Get Learning Java now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.