[an error occurred while processing this directive]
The Morgue Commentary PLAF Papers Friends Tech Topics Swing Text The Web Tech Topics What's Swing?
Index Archive Call 911 PLAF Papers Friends Tech Topics Swing Text Swing & the Web IDE Roundup Special Report Databank Page 2 Page One What's Swing?
JDK Docs Download JDK Swing API Docs Download Swing Java Tutorial
The Swing Connection The Archive PLAF Papers

The Multiplexing Look & Feel
Creating and Using Auxiliary L&Fs in Swing


    Swing's multiplexing look and feel is a special look and feel (L&F) that provides an easy way to extend the capabilities of a user interface created in Swing without having to create a new look and feel. For example, an application that is designed to generate output for users with special needs can simultaneously provide and audio output and a Braille output, along with the standard visual output that ordinary Swing applications generate.

    In this article, Swing team member Will Walker explains how the Swing's multiplexing L&F works, and provides some illustrations of how you might use the multiplexing L&F in your own Swing applications.


By Will Walker

This article shows how the Swing tool set supports the multiplexing look and feel: a special look and feel (L&F) that provides an easy way to extend the capabilities of a user interface created in Swing without having to create a new look and feel. More specifically, the article covers these major topics:

  • It describes the purpose of the multiplexing look and feel and outlines the problems that the multiplexing L&F can solve.
     
  • It shows how to use the multiplexing look and feel in Swing programs.
     
  • It briefly demonstrates how to create an auxiliary look and feel.
     
  • It describes some of the features and capabilities of the default multiplexing look and feel that comes with Swing.
     
  • It very briefly outlines some future plans for supporting the multiplexing look and feel in Swing.

This article assumes that you are familiar with Swing's concept of pluggable looks and feels (PL&Fs). If you aren't, it might be beneficial to read the article titled "An Overview of Swing Architecture" before you continue reading this article.


Overview

To simplify the task of extending the capabilities of a Swing user interface without having to create a new look and feel, Swing supports the concept of a multiplexing look and feel. When a component asks for its UI instance (that is, when it invokes the getUI() method), the multiplexing look and feel transparently creates --and simultaneously supports -- UI instances from several different look-and-feels.

This mechanism enables Swing to make use of the concept of more specialized look and feels -- known as auxiliary look and feels -- that can be combined to create an environment tailored to the needs of the end user.

For example, with the help of Swing's multiplexing look and feel, an application that makes use of a default visual look and feel can simultaneously and automatically load and maintain several auxiliary look and feels as well -- such as one for audio and another for Braille. All this can be done at the same time, and without requiring modifications to the default visual look and feel.

Without the multiplexing look and feel, a developer who wanted to enhance a particular look and feel would need to create a subclass of that look and feel. For example, to add audio support to the Metal look and feel without using the multiplexing look and feel, the developer would need to create a subclass of the Metal look and feel and add audio support to that subclass. If the developer also wanted to add audio support to other L&Fs, such as Motif or Windows, the developers would need to create subclasses of them as well.

This approach has at least two shortcomings:

  • First, each subclass must use what is essentially a copy of the same code, potentially creating a difficult support situation for the developer.
     
  • Second, and more significantly for the end user, some application developers might force the use of a particular look and feel to be used. When this approach is used, the end user can't even use Swing's enhanced look and feel subclass.

Swing's multiplexing look and feel solves both these problems simultaneously because it allows multiple look and feels to be combined. The multiplexing L&F solves the first problem (having to use what amounts to a second copy of the same code) because it allows the developer to create a specialized look and feel that can then be combined with other look and feels.

The multiplexing look and feel is also a good solution to the second problem (having to force the use of a particular L&F) because it allows a specialized look and feel to be used in conjunction with whatever default look and feel the application may have locked in place.


Using Auxiliary Look and Feels

It's easy to use auxiliary look-and-feels is with Swing. To instruct Swing to use the multiplexing look and feel, all an application has to do is modify the $JDKHOME/lib/swing.properties file to include a definition of the swing.auxiliarylaf property. Swing treats the swing.auxiliarylaf property as a comma-separated list of LookAndFeel subclasses that specify what auxiliary look-and-feels should be used in addition to the default look and feel. If at least one valid LookAndFeel subclass is specified in the swing.auxiliarylaf property, Swing automatically uses the multiplexing look and feel to load and support the default and auxiliary look and feels.

For example, let's assume that an application makes use of a look-and-feel that supports audio feedback, and also uses an L&F that that adds support to Swing for a mouse with a speed-scrolling wheel on it. Let's also assume that the audio-feedback L&F is named com.myco.AudioLookAndFeel, and that the L&F which adds speed-scrolling support to the mouse is named com.mouseco.WheelMouseLookAndFeel.

To tell Swing to use both these L&Fs -- and to use a default look and feel at the same time -- your application could simply add the following line to the $JDKHOME/lib/swing.properties file:

    swing.auxiliarylaf=com.myco.AudioLookAndFeel,
        com.mouseco.WheelMouseLookAndFeel

This statement tells Swing to obtain a component's UI from the multiplexing look and feel automatically, instead of obtaining it directly from the default look and feel. The resulting multiplexing UI is a small delegate that obtains and maintains UIs from the default and auxiliary look and feels. As a result, when a method is called in a multiplexing UI instance, the multiplexing UI will call the same method in each of the UIs obtained from the default and auxiliary look and feels.


Developing an auxiliary L&F

An auxiliary look and feel is no different from any other LookAndFeel subclass except that it doesn't have to provide all the support of a look and feel that would be used as the default look and feel. For example, an auxiliary look and feel that supports just audio feedback doesn't need to provide any code for painting. As a result, developing an auxiliary look and feel can be easier than developing a visual look and feel and also permits the developer to concentrate solely on providing just this specialized functionality. Note that the primary purpose of an auxiliary look and feel is to enhance the default look and feel. Therefore, auxiliary look and feels tend be non visual. Since an auxiliary look and feel is a LookAndFeel subclass, however, there is nothing to prevent the auxiliary look and feel from rendering information on the display.


Auxiliary L&Fs do's and don'ts

The following paragraphs provide some general recommendations for developing auxiliary look and feels.

Use installUI() and uninstallUI()

    In most cases, auxiliary look-and-feels are primarily interested in the installUI() and uninstallUI() methods of the UI. These are the methods that are called when a component's look and feel is set. They give the UI a chance to register and remove listeners on the component and its data model.

Don't Extend Visual Look and Feels

    We recommended that you don't implement UI classes of an auxiliary look and feel as subclasses of the UI classes of a visual look and feel. Why not? Because they might accidentally inherit code that installs listeners on a component instance or renders the component on the display. As a result, your auxiliary look and feel would compete with the default look and feel rather than cooperating with it.

    Instead, we recommend that the UI classes of an auxiliary look and feel directly extend the abstract UI classes in the
    swing.plaf package. By using this strategy, the developer of an auxiliary look and feel can avoid competing with the default look and feel.

What UI classes should override

    We also recommend that each UI class of an auxiliary look and feel override the methods of the swing.plaf UI class it extends. The reasons for this recommendation are similar to those given for not extending a visual look and feel (see first item, above). For example, there is a ComponentUI class that provides a default implementation for the update method. This default implementation draws on the display if the component is opaque. If a UI class from a non-visual auxiliary look and feel did not override this method, it would cause all opaque components to appear as blank areas on the screen!


When to extend UIDefaults

In many cases, you might want an auxiliary look and feel to be "incomplete." That is, your application might not want to provide the complete set of UI classes for Swing.

For example, an auxiliary look and feel might choose not to provide a LabelUI class, but may wish to provide a ButtonUI class. This option is allowed, and the multiplexing look and feel gracefully handles such situations.

By default, however, Swing issues an error message when it asks a look and feel for a UI instance and the look and feel does not support that UI. This message can be annoying, especially to auxiliary look-and-feel developers who purposely don't want to support a particular UI.

Fortunately, auxiliary L&F developers can prevent this error message from being issued by simply creating a subclass of the UIDefaults class and returning that from the getDefaults() method of the LookAndFeel:

public class MyAuxLookAndFeel extends LookAndFeel {
    ...
    public UIDefaults getDefaults() {
        UIDefaults table =
            new MyAuxUIDefaults();
        Object[] uiDefaults = {
          "ButtonUI", "MyAuxButtonUI",
          ...
        }
        table.putDefaults(uiDefaults);
        return table;
    }
}

class MyAuxUIDefaults extends UIDefaults {
    protected void getUIError(String msg) {
        //System.err.println
        //   ("An annoying message!");
    }
}

In the preceding example, an auxiliary look and feel named MyAux creates a UIDefaults subclass that overrides the getUIError() method. The getUIError() method is the method that is called when Swing cannot find a UI instance in a look and feel. By merely doing nothing in this method, you can avoid the error message.


Examining UI instances from other L&Fs

In some rare instances, a UI instance from an auxiliary look and feel may be interested in the default UI instance used by the component. In these cases, the UI instance from auxiliary look and feel can obtain the UI from a component by calling its getUI() method. If the resulting UI is an instance of one of the multiplexing look and feel UI classes from the default multiplexing look and feel (e.g., MultiButtonUI), the UI instance from the auxiliary look and feel can call the getUIs method of this object to obtain an array containing complete list of all UIs handled by the multiplexing factory. The first element (i.e., element[0]) is guaranteed to be the UI created from the default look and feel.


The Default Multiplexing L&F

The multiplexing look and feel itself is meant to be transparent to all developers and users. It should "just work" -- and it is used only when the user tells Swing to use an auxiliary look and feel.

There may be cases, however, where the implementation of the default multiplexing look and feel does not meet a developer's needs. This section describes the implementation of the default multiplexing look and feel and also provides details for how to replace it with a different one.

The default multiplexing look and feel, swing.plaf.multi.MultiLookAndFeel, is stored in the multi.jar file that is shipped with Swing. When the multiplexing look and feel is in use, each component requesting a UI instance actually gets an instance of a multiplexing UI instead of an instance of a UI from the default look and feel. The default multiplexing UI obtains and maintains UIs from the default and auxiliary look-and-feels, and refers to these UIs in the following manner:

  • The UI instance from the default look and feel is always the first to be created. After that, a UI instance will be created from each auxiliary look and feel in the order they are specified in the swing.auxiliarylaf property.
     
  • When a method that requests information from a UI instance is invoked, the multiplexing UI instance returns only the results from the UI that are obtained from the default factory. For example, when the getPreferredSize() method is invoked on a multiplexing UI, the UI returns only the results of getPreferredSize() on the UI obtained from the default factory. The rest of the UIs obtained from the auxiliary factories are ignored.
     
  • When a method that does not request information from the UI instance is invoked, the multiplexing UI instance invokes that method on the UI obtained from the default factory and all the UIs obtained from the auxiliary factories as well. For example, invoking the installUI() method on a multiplexing UI causes the multiplexing UI to invoke installUI() on UI obtained from the default factory and the UIs obtained from the auxiliary factories.

In all cases, the UI instance obtained from the default look and feel is acted upon first, and then the auxiliary look and feels are acted upon in the order they are specified in the swing.auxiliarylaf property. 


Overriding the Default L&F

While we hope the behavior of the default multiplexing look and feel is flexible enough not to require an alternative multiplexing look and feel, Swing allows the user to specify the multiplexing look and feel to use.

To do that, all the user has to do is modify the $JDKHOME/lib/swing.properties file to include a definition of the swing.plaf.multiplexinglaf property. Swing then treats the swing.plaf.multiplexinglaf property as a LookAndFeel subclass that supports multiplexing.

For example, if a user has a multiplexing look and feel named com.myco.SuperMultiLookAndFeel that is a better match for their needs than the default multiplexing look and feel provided by swing.plaf.MultiLookAndFeel, the user could include the following line in $JDKHOME/lib/swing.properties:

swing.plaf.mulitplexinglaf =
com.myco.SuperMultiLookAndFeel

This statement instructs Swing to use com.myco.SuperMultiLookAndFeel instead of swing.plaf.MultiLookAndFeel. But if you use this kind of statement, be careful, because the suppliers of auxiliary look-and-feels will most likely have developed and tested against Swing's default multiplexing look and feel.


What's Next

In the current release of Swing, the multiplexing look and feel is meant to be relatively latent; there's just enough there to support developers who have requested such a feature. In the future, work on the multiplexing look and feel will include additions to the UIManager class that will allow procedural determination of the auxiliary and multiplexing look and feels.

[an error occurred while processing this directive]