26.4 The MultiLookAndFeel


Before we get into creating our own L&F, we'll take a quick detour to explore MultiLookAndFeel. This is the L&F that allows accessible interfaces to be incorporated into Swing applications. It can also be used to add sound effects, support for automated testing, and more.

By this point, you're probably at least aware of the concept of accessibility as it applies to JFC and Swing. If you read Chapter 25, you're aware of more than just the concept. The last piece of the accessibility puzzle is Swing's multiple L&F support.

The idea behind MultiLookAndFeel is to allow multiple L&Fs to be associated with each component in a program's GUI without the components having to do anything special to support them. By allowing multiple L&Fs, Swing makes it easy to augment a traditional L&F with auxiliary L&Fs, such as speech synthesizers or braille generators. Figure 26-10 gives a high-level view of how this might work.

Figure 26-10. MultiLookAndFeel and Auxiliary L&F
figs/swng2.2610.gif

In this diagram, we show a JButton in a multiplexing UI environment. The button's UI delegate is actually a MultiButtonUI, which is contained in the javax.swing.plaf.multi package. This is a special delegate that can support any number of additional ButtonUI objects. Here, we show the default UI delegate (MetalButtonUI) and two (hypothetical) auxiliary delegates, AudioButtonUI and BrailleButtonUI.

The MultiButtonUI (and all the other multiplexing delegates) keeps track of a vector of "real" UI objects. The first element in the vector is guaranteed to be the default, screen-based L&F. This default receives special treatment. When the JButton sends a query to its UI delegate, the MultiButtonUI forwards the query first to its default L&F, and then to each of the auxiliary L&Fs. If the method requires a return value, only the value returned from the default L&F is used; the others are ignored.

26.4.1 Creating an Auxilliary Look-and-Feel

Creating a fully implemented auxiliary L&F is beyond the scope of this book. However, we will throw something together to give you a feel for what it would take to build one.

In this example, we define an L&F called StdOutLookAndFeel. This simple-minded L&F prints messages to the screen to describe which component has the focus. To make the example reasonably concise, we show only the implementation of the UI delegate for JButtons, which does nothing more than print messages when a button gains or loses focus.

First, let's take a look at our StdOutLookAndFeel class:

// StdOutLookAndFeel.java // import javax.swing.*; import javax.swing.plaf.*; public class StdOutLookAndFeel extends LookAndFeel {   // A few simple informational methods   public String getName( ) { return "Standard Output"; }   public String getID( ) { return "StdOut"; }   public String getDescription( ) { return "The Standard Output Look and Feel"; }   public boolean isNativeLookAndFeel( ) { return false; }   public boolean isSupportedLookAndFeel( ) { return true; }   // Our only default is the UI delegate for buttons.   public UIDefaults getDefaults( ) {     UIDefaults table = new UIDefaults( );     table.put("ButtonUI", "StdOutButtonUI"); // In order to function, we'd also need lines here to define UI delegates // extending each of the following classes: CheckBoxUI, ComboBoxUI, // DesktopIconUI, FileChooserUI, InternalFrameUI, LabelUI, // PopupMenuSeparatorUI, ProgressBarUI, RadioButtonUI, ScrollBarUI, // ScrollPaneUI, SeparatorUI, SliderUI, SplitPaneUI, TabbedPaneUI, // TextFieldUI, ToggleButtonUI, ToolBarUI, ToolTipUI, TreeUI, and RootPaneUI.     return table;   } }

As you can see, we've left out a lot of defaults that would be required for our L&F to be usable. In our case, we just map "ButtonUI" (the value of the UIClassID property for JButton) to our StdOutButtonUI class. Let's take a look at that class now:

// StdOutButtonUI.java // import java.awt.*; import java.awt.event.*; import javax.accessibility.*; import javax.swing.*; import javax.swing.plaf.*; public class StdOutButtonUI extends ButtonUI {   // Use a single instance of this class for all buttons.   private static StdOutButtonUI instance;   private AccessListener listener = new AccessListener( );   // Return the single instance. If this is the first time, we create the   // instance in this method too.   public static ComponentUI createUI(JComponent c) {     if (instance == null) {       instance = new StdOutButtonUI( );     }     return instance;   }   // Add a focus listener so we know when the buttons have focus.   public void installUI(JComponent c) {     JButton button = (JButton)c;     button.addFocusListener(listener);   }   // Remove the focus listener.   public void uninstallUI(JComponent c) {     JButton button = (JButton)c;     button.removeFocusListener(listener);   }   // Empty paint and update methods. An empty update( ) is critical!   public void paint(Graphics g, JComponent c) {   }   public void update(Graphics g, JComponent c) {   }   public Insets getDefaultMargin(AbstractButton b) {     return null; // Not called since we're auxiliary   }   // A focus listener. A real L&F would want to do a lot more.   class AccessListener extends FocusAdapter {     // We print some accessibility info when we get focus.     public void focusGained(FocusEvent ev) {       JButton b = (JButton)ev.getComponent( );       AccessibleContext access = b.getAccessibleContext( );       System.out.print("Focus gained by a ");       System.out.print(access.getAccessibleRole( ).toDisplayString( ));       System.out.print(" named ");       System.out.println(access.getAccessibleName( ));       System.out.print("Description: ");       System.out.println(access.getAccessibleDescription( ));     }     // We print some accessibility info when we lose focus.     public void focusLost(FocusEvent ev) {       JButton b = (JButton)ev.getComponent( );       AccessibleContext access = b.getAccessibleContext( );       System.out.println("Focus leaving " + access.getAccessibleName( ));     }   } }

The first method in this class is the static createUI( ) method, which is called to create an instance of our UI delegate. We chose to share an instance of StdOutButtonUI across all buttons, so we just return our single instance from this method. The next two methods, installUI( ) and uninstallUI( ), are used to add and remove a FocusListener from the button. In a more realistic implementation, you'd likely be interested in listening for other types of events as well this is where you'd register (and unregister) them.

Next, we define empty implementations of paint( ) and update( ). Note the comment about the update( ) method. If we didn't override the default update( ) implementation, our auxiliary L&F, which should not affect the display in any way, would paint a solid rectangle in the location of opaque components.

We've also defined a small inner class called AccessListener. We've just made this class a FocusListener that displays a little information about the button any time it gains or loses focus. Note that we've taken advantage of Swing's support for accessibility by pulling information from the button's AccessibleContext.

26.4.2 Installing the MultiLookAndFeel

At this point, you may be wondering exactly how you use this new L&F. Obviously, we can't just call UIManager.setLookAndFeel( ) because we'd lose our graphical L&F that way. Luckily, Swing provides us with three other ways to install our auxiliary L&F. The first option is to explicitly tell the UIManager about the L&F. Placing the following line in our main( ) (or init( ) for an applet) method does the trick:

UIManager.addAuxiliaryLookAndFeel (new StdOutLookAndFeel ( ) );

The second option is to use the Swing properties we discussed earlier in the chapter. If you want to make a global addition of the L&F, add the following to your swing.properties file:

swing.auxiliarylaf=StdOutLookAndFeel

The last option is very convenient if you're just playing around. All you have to do is tell the Java runtime about the L&F when you start it up, like this:

% java -Dswing.auxiliarylaf=StdOutLookAndFeel YourApp

Although this example is very sketchy, it should give you a sense of how to get started creating an auxiliary L&F and of the amount of work it takes.



Java Swing
Graphic Java 2: Mastering the Jfc, By Geary, 3Rd Edition, Volume 2: Swing
ISBN: 0130796670
EAN: 2147483647
Year: 2001
Pages: 289
Authors: David Geary

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