Metalを自由に変更できますか?
ルックアンドフィールというのは基本的に主なOS用に用意されているものですが、その中でJava独自のものとして用意されているのが「Metal」です。非常にシンプルですが、独特の雰囲気を持ったルックアンドフィールです。
このMetalは、他のルックアンドフィールにはない特徴があります。それは、ルックアンドフィールの表示(各コンポーネントの色やフォントなど)を簡単にカスタマイズすることができるという点です。Metalのためのルックアンドフィール・クラスを継承して独自にプロパティを定義することで、オリジナルな色合いのMetalルックアンドフィールを作れます。
実際に、ごく簡単なMetalルックアンドフィール・クラスを作成してみましょう。「MyMetalTheme」というクラスを作成し、次のように定義してください。
package jp.codezine; import java.awt.Color; import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.metal.DefaultMetalTheme; public class MyMetalTheme extends DefaultMetalTheme { private final String name; private final ColorUIResource primary1; private final ColorUIResource primary2; private final ColorUIResource primary3; private final ColorUIResource secondary1; private final ColorUIResource secondary2; private final ColorUIResource secondary3; private final ColorUIResource menuForeground; private final ColorUIResource menuBackground; private final ColorUIResource menuSelectedForeground; private final ColorUIResource menuSelectedBackground; public MyMetalTheme(){ name = "MyMetal"; primary1 = new ColorUIResource(new Color(150,100,100)); primary2 = new ColorUIResource(new Color(200,100,100)); primary3 = new ColorUIResource(new Color(255,200,200)); secondary1 = new ColorUIResource(new Color(120,90,90)); secondary2 = new ColorUIResource(new Color(150,120,120)); secondary3 = new ColorUIResource(new Color(255,220,220)); menuForeground = new ColorUIResource(new Color(255,150,150)); menuBackground = new ColorUIResource(new Color(75,50,50)); menuSelectedForeground = new ColorUIResource(new Color(50,0,0)); menuSelectedBackground = new ColorUIResource(new Color(200,160,160)); } @Override public String getName() { return name; } @Override protected ColorUIResource getPrimary1() { return primary1; } @Override protected ColorUIResource getPrimary2() { return primary2; } @Override protected ColorUIResource getPrimary3() { return primary3; } @Override protected ColorUIResource getSecondary1() { return secondary1; } @Override protected ColorUIResource getSecondary2() { return secondary2; } @Override protected ColorUIResource getSecondary3() { return secondary3; } @Override public ColorUIResource getMenuBackground() { return menuBackground; } @Override public ColorUIResource getMenuForeground() { return menuForeground; } @Override public ColorUIResource getMenuSelectedBackground() { return menuSelectedBackground; } @Override public ColorUIResource getMenuSelectedForeground() { return menuSelectedForeground; } }
Metalのテーマの仕組み
Metalルックアンドフィールは、javax.swing.plaf.metal.MetalTheme抽象クラスを継承した「DefaultMetalTheme」というクラスを「テーマ」として設定し表示します。テーマというのは、各コンポーネントの色やフォントなどのセットのことです。このテーマを新たに定義し、Metalルックアンドフィールに設定することで、Metalの表示色などをカスタマイズできるのです。
DefaultMetalThemeには、以下の6つのメソッドが用意されています。これらで返すColorUIResourceによって、コンポーネント類の表示色が決められます。
protected ColorUIResource getPrimary1(); protected ColorUIResource getPrimary2(); protected ColorUIResource getPrimary3(); protected ColorUIResource getSecondary1(); protected ColorUIResource getSecondary2(); protected ColorUIResource getSecondary3();
返値のColorUIResourceは、引数にColorを渡してnewし作成します。これにより、引数に指定した色のColorUIResourceが用意できます。これらのメソッドを用意するだけですから、クラスの作成は非常に単純です。
ただし、これだけでは細かな表示が行えません。特に重要なのは、メニュー関係でしょう。このままだと、コンポーネントもメニューもすべて同じ色合いになってしまいます。そこで、ここではDefaultMetalThemeのスーパークラスであるMetalThemeのメニュー関係のメソッドをオーバーライドして、メニューの色を独自に定義しています。
public ColorUIResource getMenuForeground(); public ColorUIResource getMenuBackground(); public ColorUIResource getMenuSelectedForeground(); public ColorUIResource getMenuSelectedBackground();
これらを用意することで、メニューの通常状態と選択状態の前景色・背景色をそれぞれ設定できます。この他にもMetalThemeにはフォント関係などいくつものメソッドが用意されています。
MyMetalThemeで表示する
では、作成したMyMetalThemeをテーマに設定して、アプリケーションを表示させてみましょう。先ほどのSampleAppを修正して、独自のMetalルックアンドフィールでアプリケーションを表示させてみます。コンストラクタとcreateComponentを次のように修正します。
// import javax.swing.plaf.metal.*; public SampleApp(){ this.setSize(new Dimension(200,200)); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); GridLayout layout = new GridLayout(4,1); layout.setHgap(5); layout.setVgap(5); this.setLayout(layout); MetalLookAndFeel.setCurrentTheme(new MyMetalTheme()); try { UIManager.setLookAndFeel(new MetalLookAndFeel()); SwingUtilities.updateComponentTreeUI(this); } catch (UnsupportedLookAndFeelException e) { e.printStackTrace(); } createComponent(); } public void createComponent(){ JMenuBar mbar = new JMenuBar(); JMenu menu = new JMenu("File"); menu.add(new JMenuItem("Test")); menu.add(new Separator()); menu.add(new JMenuItem("Quit")); mbar.add(menu); this.setJMenuBar(mbar); JCheckBox check = new JCheckBox("checkbox"); this.add(check); JRadioButton radio = new JRadioButton("radio"); this.add(radio); combo = new LaFComboBox(); combo.addActionListener(this); this.add(combo); JButton btn = new JButton("button"); this.add(btn); }

テーマの設定は、MetalLookAndFeel.setCurrentThemeを呼び出して行います。ここで引数にテーマ・クラスのインスタンスを渡すだけです。その後、UIManager.setLookAndFeelを使ってルックアンドフィールを設定し、SwingUtilities.updateComponentTreeUIで更新を行っておきます。
ここでは、setLookAndFeelの引数にLookAndFeelクラスを指定しています。この場合、発生する例外はUnsupportedLookAndFeelExceptionだけですので、Stringでクラス名を指定するよりもずいぶんcatch節がすっきりしますね。
まとめ
今回は、ボーダーやルックアンドフィールといった、コンポーネントの表示関係についていくつかのテクニックを紹介しました。特にルックアンドフィールの変更などは、いかにもSwingらしい機能と言えるでしょう。こうした機能を使いこなせるようになると、Swingの柔軟さを実感できるはずです。
基本的なコンポーネントだけでも、こうした機能を使いこなすことで思った以上に高度なレイアウトを作成していくことができます。コンポーネント活用と言うとすぐに「オリジナルコンポーネントの開発」に飛びついてしまう感じがありますが、まず基本的なコンポーネントを徹底的に使いこなすことから考えましょう。案外、それで済んでしまうことの方が多いのではないでしょうか。
