多重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つの短所があります。

  • 最初に、各サブクラスは実質的には同じコードのコピーを使用する必要があり、開発者にとってサポートが困難な状況をもたらす可能性があります。
  • 2番目に、エンド・ユーザーにはさらに重要なことですが、一部のアプリケーション開発者から特定のLook & Feelを使用するように強制される場合があります。 この方法が使用されると、エンド・ユーザーは拡張されたLook & Feelを使用することさえできません。

多重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にマルチプレクスのルック・アンド・フィールを使用させるためには、swing.auxiliarylafプロパティの定義を含むように$JDKHOME/conf/swing.propertiesファイルを変更するだけです。 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に指示するには-- デフォルトのルック・アンド・フィールを同時に使用-- あなたのアプリケーションは単に$JDKHOME/conf/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の開発における一般的な推奨事項についていくつか説明します。

Use the installUI method to perform all initialization, and the uninstallUI method to perform all cleanup.

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

Don't extend visual look and feels.

視覚的なルック・アンド・フィールのUIクラスのサブクラスとして補助的なルック・アンド・フィールのUIクラスを実装しないことをお勧めします。 何故なの? 誤ってコンポーネント・オブジェクトにリスナーをインストールするコードを継承したり、コンポーネントをディスプレイにレンダリングする可能性があるためです。 その結果、補助的なルック・アンド・フィールは、それと協調するのではなく、デフォルトのルック・アンド・フィールと競合します。

その代わりに、補助的なルック・アンド・フィールのUIクラスは、javax.swing.plafパッケージ内の抽象UIクラスを直接拡張することを推奨します。
この戦略を使用することにより、補助的なルック・アンド・フィールの開発者は、デフォルトのルック・アンド・フィールと競合することを避けることができます。

Override all UI-specific methods your UI classes inherit.

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

UIDefaultsの拡張

多くの場合、補助的なルック&フィールを"incomplete." つまり、コンポーネントの完全なセットをサポートする必要はないかもしれません。 たとえば、補助的な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という名前の補助ルック・アンド・フィールは、getUIErrorメソッドをオーバーライドするUIDefaultsサブクラスを作成します。 getUIErrorメソッドは、Swingがルック・アンド・フィールでUIオブジェクトを見つけることができないときに呼び出されるメソッドです。 このメソッドで何もしないだけで、エラー・メッセージを回避できます。

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

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


多重Look &Feelの実装方法

多重化ルック・アンド・フィール(javax.swing.plaf.multi.MultiLookAndFeelで表される)は、すべての開発者とユーザーに透過的であるように意図されています。 それは"ただ仕事"する必要があります -- ユーザーが補助的なルック・アンド・フィールを使用するようにSwingに指示した場合にのみ使用されます。

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

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

  • デフォルトLook & FeelのUIオブジェクトは常に最初に作成されます。 そのあとは、UIオブジェクトが、swing.auxiliarylafプロパティで指定されている順序で、それぞれの補助的なLook &Feelから作成されます。

  • UIオブジェクトに情報を要求するメソッドが呼び出されると、多重UIオブジェクトはすべてのUIオブジェクトのそのメソッドを呼び出しますが、デフォルトLook & FeelのUIからの結果のみを返します。 たとえば、多重UIのgetPreferredSizeメソッドが呼び出されると、このUIは、デフォルトLook & Feelから取得したUIのgetPreferredSizeの呼出しの結果のみを返します。 また、それぞれの補助的なLook &FeelのUIオブジェクトのgetPreferredSizeメソッドも呼び出されますが、戻り値は無視されます。

  • UIオブジェクトからの情報を要求しないメソッドが呼び出されると、多重UIオブジェクトはすべてのUI (デフォルトLook & Feelから取得したUIオブジェクトだけでなく、補助的なLook & Feelから取得したすべてのUIも)でそのメソッドを呼び出します。 たとえば、多重UIのinstallUIメソッドを呼び出すと、多重UIは、デフォルトLook & Feelから取得したUIと、補助的なファクトリから取得したUIでinstallUIを呼び出します。

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


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

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

これを行うには、swing.plaf.multiplexinglafプロパティの定義を組み込むように、$JDKHOME/conf/swing.propertiesファイルを変更するだけです。 Swingは、swing.plaf.multiplexinglafプロパティを多重化をサポートするLookAndFeelサブクラスとして扱います。

たとえば、com.myco.SuperMultiLookAndFeelで表される多重化ルック・アンド・フィールが、Multiplexingルック・アンド・フィール(javax.swing.plaf.multi.MultiLookAndFeel)よりもニーズに合っている場合、ユーザーは$JDKHOME/conf/swing.propertiesに次の行を含めることができます:

swing.plaf.multiplexinglaf = com.myco.SuperMultiLookAndFeel

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