多重Look & Feelの使用

このドキュメントは、最初に「The Swing Connection」で公開された記事に基づいています。


多重Look & Feelを使用すると、通常のLook & Feel (デフォルト Look & Feel)を1つ以上の補助 Look & Feelで補足できます。たとえば、2つの補助のLook & Feel (1つは音声読上げ用、もう1つは点字用)をデフォルトLook & Feelに追加することにより、Swingベース・アプリケーションが生成する通常の表示出力に加えて、同時に音声読上げ出力や点字出力を提供できます。デフォルトLook & Feelは任意の通常のLook & Feel (JavaやWindowsのLook & Feelなど)にすることができ、補助のLook & Feelと連携するための変更は不要です。

このドキュメントには次のセクションがあります。

このドキュメントを読み進める前に、プラグイン可能なLook & Feelの概念に習熟しておくようにしてください。基本的な情報については、「The Java Tutorial」のセクション「How to Set the Look and Feel」を参照してください。アーキテクチャの詳細については、「Swing Connection」記事内のセクション「Pluggable look-and-feel architecture」を参照してください。


概要

javax.swing.plaf.multiパッケージ内のクラスは多重Look & Feelを実装します。多重Look & Feelは、UIオブジェクトを要求(getUIメソッドを使用)するコンポーネントに応答して、複数の異なるLook & FeelからUIオブジェクトを透過的に作成し、同時にサポートします。

多重Look & Feelを使用しない場合、特定のLook & Feelを拡張する開発者はLook & Feelをサポートするクラスの継承が必要になります。たとえば、多重Look & Feelを使用しないで音声読上げサポートをJava Look & Feelに追加する場合、開発者はJava Look & Feelのクラスを継承したクラスのグループを作成して、音声読上げのサポートをこの新しいクラスに追加する必要があります。また、開発者が音声読上げのサポートをその他のLook & Feel (MotifやWindowsなど)にも追加する場合、これらのクラスのサブクラスも作成する必要があります。

この方法には次のように少なくとも2つの短所があります。

多重Look & Feelでは、複数のLook & Feelを組み合わせることができるため、これらの2つの問題が同時に解決されます。最初の問題(同じコードの別のコピーを使用する必要がある)は、開発者が特別なLook & Feelを作成してその他のLook & Feelと組み合わせることができるため、解決されます。

2番目の問題(特定のLook & Feelの使用を強制する必要がある)は、すでにロック済みの可能性があるデフォルトLook & Feelが何であれ、特別なLook & Feelを一緒に使用できるため、解決されます。

デフォルトの多重Look & Feelの実装は、javax.swing.plaf.multiパッケージ内のMultiLookAndFeelクラスで表され、(そのままの)多重Look & Feelという名前です。


補助的なLook &Feelの使用方法

補助的なLook & FeelをSwingとともに使用するのは容易です。Swingに多重Look & Feelを使用するように指示するには、すべてのアプリケーションで$JDKHOME/lib/swing.propertiesファイルを変更して、swing.auxiliarylafプロパティの定義を含める必要があります。Swingはswing.auxiliarylafプロパティをLookAndFeelサブクラスのカンマ区切りのリストとみなしますが、これらのサブクラスは、デフォルトLook & Feelのほかに使用すべき補助的なLook & Feelを指定します。有効なLookAndFeelサブクラスがswing.auxiliarylafプロパティに少なくとも1つ指定されていると、Swingは自動的にその多重Look & Feelを使用し、デフォルトおよび補助的なLook & Feelのロードとサポートを行います。

たとえば、アプリケーションが音声読上げフィード・バックをサポートするLook & Feelを使用し、香りを発するデバイスのサポートを追加するLook & Feelも使用するとします。音声読み上げLook & Feelの名前はcom.myco.TextTalkerLookAndFeelであり、香りのサポートを追加するLook & Feelの名前はcom.smellco.OlfactoryLookAndFeelとします。

Swingに、これら2つのLook & Feelを使用し、同時にデフォルトLook & Feelも使用するように指示するには、アプリケーションで単に次の行を$JDKHOME/lib/swing.propertiesファイルに追加するだけです。

    swing.auxiliarylaf=com.myco.TextTalkerLookAndFeel,
        com.smellco.OlfactoryLookAndFeel

この文は、コンポーネントのUIをデフォルトLook & Feelから直接取得する代わりに、多重Look & Feelから自動的に取得するようにSwingに指示します。結果として得られる多重UIは、デフォルトおよび補助的なLook & FeelからUIを取得して維持する小さな委譲先です。この結果、多重UIオブジェクトのメソッドが呼び出されると、多重UIは、デフォルトおよび補助的なLook & Feelから取得した各UIの同じメソッドを呼び出します。


補助的なLook &Feelを書く場合のヒント

補助的なLook & Feelは、デフォルトLook & Feelが提供する必要がある完全なサポートを提供する必要がない点を除いて、その他のLook & Feelと同様です。たとえば、音声読上げフィード・バックのみをサポートする補助的なLook & Feelは、ペイント用のコードを提供する必要はありません。また、すべてのコンポーネントをサポートする必要がない場合があります。たとえば、JSeparatorは無視されることがあります。

補助的なLook & Feelは単純な傾向があるため、視覚的なLook & Feelよりも開発が容易な可能性があります。開発者は特別な機能を用意することのみに集中できます。

補助的なLook & Feelの主な目的はデフォルトLook & Feelを拡張することにあるため、補助的なLook & Feelは非視覚的になる傾向があります。ただし、補助的なLook & Feelも純粋なLook & Feelであるため、画面に情報をレンダリングしても構いません。

ほかのLook & Feelの場合と同様、補助的なLook & Feelを実装するには、javax.swing.LookAndFeelのサブクラスを記述し、javax.swing.plafパッケージに定義されているFooUIクラスのサブクラスを作成します。


注意事項

次の段落では、補助的なLook & Feelの開発における一般的な推奨事項についていくつか説明します。

すべての初期化を実行する場合はinstallUIメソッドを使用し、すべてのクリーンアップを実行する場合はuninstallUIメソッドを使用します。

コンポーネントのLook & Feelが設定されると、installUIおよびuninstallUIメソッドが呼び出されます。installUIメソッドにより、新しいUIオブジェクトはコンポーネントおよびそのデータ・モデルにリスナーを追加できます。同様に、uninstallUIメソッドにより、そのUIオブジェクトはリスナーを削除できます。

視覚的なLook & Feelを継承しないでください。

補助的なLook & FeelのUIクラスを視覚的なLook & FeelのUIクラスのサブクラスとして実装しないことをお薦めします。 理由は次のとおりです。リスナーをコンポーネント・オブジェクトにインストールしたりコンポーネントを画面にレンダリングしたりするコードを誤って継承する場合があるためです。 その結果、補助的なLook & FeelはデフォルトLook & Feelと協調するのではなく、競合する可能性があります。

代わりに、補助的なLook & FeelのUIクラスがjavax.swing.plafパッケージの抽象UIクラスを直接継承することをお薦めします。 この方法を使用すると、補助的なLook & FeelがデフォルトLook & Feelと競合することを避けることができます。

UIクラスが継承するUI固有のすべてのメソッドをオーバーライドします。

補助的なLook & Feelの各UIクラスは派生元のjavax.swing.plaf UIクラスに定義されているメソッドをオーバーライドすることをお薦めします。この推奨事項の理由は、視覚的なLook & Feelを継承しない理由と同様です。たとえば、すべてのUIクラスの派生元のComponentUIクラスはupdateメソッドのデフォルト実装を提供します。このデフォルト実装では、コンポーネントが不透明の場合に画面にペイントします。非視覚的で補助的なLook & FeelのUIクラスがこのメソッドをオーバーライドしないと、すべてが不透明なコンポーネントが空白領域として画面に表示されてしまいます。


UIDefaultsの拡張

多くの場合、補助的なLook & Feelが「不完全」になる場合があります。 つまり、コンポーネントの完全なセットをサポートする必要がない場合があります。たとえば、補助的なLook & FeelはButtonUIサブクラスを提供して、LabelUIサブクラスを提供しない場合があります。こうした選択は可能であり、多重Look & Feelはこのような状況を適切に処理します。

ただしデフォルトでは、Swingは、Look & FeelにUIオブジェクトを要求してLook & FeelがそのUIをサポートしない場合、エラー・メッセージを発行します。特に、補助的なLook & Feelの開発者が特定のコンポーネントをサポートする予定がない場合、このメッセージは迷惑な場合があります。

幸い、UIDefaultsクラスのサブクラスを作成し、そのインスタンスをLookAndFeelクラスのgetDefaultsメソッドから返すことにより、このエラー・メッセージを回避できます。たとえば、

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!");
    }
}

前述の例では、MyAuxという補助的なLook & FeelはgetUIErrorメソッドをオーバーライドするUIDefaultsサブクラスを作成します。 getUIErrorメソッドは、SwingがLook & FeelのUIオブジェクトを検出できなかった場合に呼び出されるメソッドです。 単にこのメソッドで何もしなければ、エラー・メッセージを回避できます。


その他のUIオブジェクトの調査

まれに、補助的なLook & FeelのUIオブジェクトが、コンポーネントに使用されるデフォルトUIオブジェクトに関心がある場合があります。 この場合、補助的なLook & FeelのUIオブジェクトはgetUIメソッドを呼び出すことで、コンポーネントからUIを取得できます。 返されるUIは、いずれかの多重Look & Feel UIクラス(MultiButtonUIなど)のインスタンスです。補助的なLook & FeelのUIオブジェクトは、返されたオブジェクトのgetUIsメソッドを呼び出して、多重UIによって処理されるすべてのUIオブジェクトの完全なリストが含まれた配列を取得できます。最初の要素は、デフォルトのLook & Feelから作成されたUIであることが保証されます。


多重Look &Feelの実装方法

javax.swing.plaf.multi.MultiLookAndFeelで表される多重Look & Feelは、すべての開発者およびユーザーに対して透過的であるように作成されています。 それは「とにかく動作」すべきであり、ユーザーがSwingに補助的なLook & Feelを使用するように指示した場合にのみ使用されます。

多重Look & Feelが使用されている場合、各コンポーネントに関連付けられたUIオブジェクトの型は、現在使用中の任意の補助的なLook & Feelがそのコンポーネントをサポートするかどうかにより異なります。その場合、コンポーネントのUIオブジェクトは多重UIのインスタンスです。デフォルトLook & Feelのみがコンポーネントをサポートする場合、補助的なLook & Feelがインストールされていないかのように、そのコンポーネントはUIオブジェクトをデフォルトLook & Feelから取得します。

多重UIオブジェクトは、UIオブジェクトをデフォルトおよび補助的なLook & Feelから取得して維持し、これらのUIを次の方法で参照します。

すべての場合で、デフォルトLook & Feelから取得したUIオブジェクトが最初に処理され、補助的なLook & Feelはswing.auxiliarylafプロパティで指定されている順序で処理されます。


カスタム多重Look &Feelの提供方法

多重Look &Feelの動作が代わりの多重Look &Feelを必要としないほど柔軟になるのが望ましいことですが、Swingでは、ユーザーは使用する別の多重Look &Feelを指定できます。

これを実行するには、ユーザーが$JDKHOME/lib/swing.propertiesファイルを変更してswing.plaf.multiplexinglafプロパティの定義を含めるだけです。 その後、Swingはswing.plaf.multiplexinglafプロパティを、多重をサポートするLookAndFeelのサブクラスとみなします。

たとえば、多重Look & Feel (javax.swing.plaf.multi.MultiLookAndFeel)よりもニーズに合うcom.myco.SuperMultiLookAndFeelで表される多重Look & Feelをユーザーが持っている場合、ユーザーは次の行を$JDKHOME/lib/swing.propertiesに含めることができます。

swing.plaf.multiplexinglaf = com.myco.SuperMultiLookAndFeel

この文はSwingにjavax.swing.plaf.multi.MultiLookAndFeelの代わりにcom.myco.SuperMultiLookAndFeelを使用するように指示します。ただし、補助的なLook & Feelの供給者は標準の多重Look & Feelに対して開発しテストしている可能性が高いため、この種類の文を使用する場合は注意してください。