2006年11月01日

Look & Feel を自作する方法

【概要】
Look & Feel を自作する方法の紹介。自分好みの Look & Feel を作成して使用したり、公開したりするための Tips。

【キーワード】
Look & Feel、Look And Feel、lnf、ルック&フィール、自作、つくり方

【詳細】
1. テスト用アプリケーションの作成

まずは Look & Feel の違いを確認するための簡単な GUI アプリケーションを作成する。ここではテキストフィールドとボタンからなる、次のようなシンプルなアプリケーションを作成する。ここでは特に Look & Feel を指定していないので、アプリケーションはデフォルトの Metal Look & Feel で起動する。

[プログラム: LookAndFeelTest.java]

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class LookAndFeelTest {
  public static void main(String[] args) {
    JFrame frame = new JFrame("Look & Feel サンプル");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel panel = new JPanel();
    
    JTextField textField = new JTextField(10);
    JButton button = new JButton("検索");

    frame.getContentPane().add(panel);

    panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.add(Box.createHorizontalGlue());
    panel.add(textField);
    panel.add(Box.createHorizontalStrut(5));
    panel.add(button);
    panel.add(Box.createHorizontalGlue());
    
    frame.pack();
    frame.setVisible(true);
  }
}

[実行結果]

DefaultLook&Feel

2. Look & Feel 作成の下準備

次に、Look & Feel を作成するための準備として、空の Look & Feel を作成する。この段階では最も基本的な Look & Feel である Basic Look & Feel を継承しただけでそれ以上何もしていないので、次のようなシンプルな Look & Feel でアプリケーションが起動する。

[プログラム: MyLookAndFeel.java]

import javax.swing.plaf.basic.BasicLookAndFeel;

public class MyLookAndFeel extends BasicLookAndFeel {
  public String getDescription() {
    return "This is My Look & Feel.";
  }

  public String getID() {
    return "MyLookAndFeel";
  }

  public String getName() {
    return "My Look & Feel";
  }

  public boolean isNativeLookAndFeel() {
    return false;
  }

  public boolean isSupportedLookAndFeel() {
    return true;
  }
}

[プログラム: LookAndFeelTest.java]

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;

public class LookAndFeelTest {
  public static void main(String[] args) {
    try {
      UIManager.setLookAndFeel(new MyLookAndFeel());
    } catch (Exception e) {
    }
  
    JFrame frame = new JFrame("Look & Feel サンプル");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel panel = new JPanel();
    
    JTextField textField = new JTextField(10);
    JButton button = new JButton("検索");

    frame.getContentPane().add(panel);

    panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.add(Box.createHorizontalGlue());
    panel.add(textField);
    panel.add(Box.createHorizontalStrut(5));
    panel.add(button);
    panel.add(Box.createHorizontalGlue());
    
    frame.pack();
    frame.setVisible(true);
  }
}

[実行結果]

BasicLook&Feel

3. メタリックな Look & Feel の作成

次に、自作する Look & Feel をメタリックなテイストのものにするために、いくつかのクラスを用意する。これらを用意した後にアプリケーションを起動すると、先ほどののっぺりとした Basic Look & Feel に陰影が付き、アプリケーションの雰囲気が変わる。

(最小限のシンプルな例にするために、ここではテキストフィールドとボタンの Look & Feel のみを作成する。また、UI クラスをゼロから作ってしまうとコードが膨大な量になってしまうので、ここでは Basic Look & Feel の部品を利用しつつ、その上に独自の装飾をかぶせることで独自の Look & Feel を実現している)

[プログラム: MyTextFieldUI.java]

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicTextFieldUI;

public class MyTextFieldUI extends BasicTextFieldUI {
  private static final Color GRADATION_START =
      new Color(255, 255, 255, 0);
  private static final Color GRADATION_END =
      new Color(0, 0, 0, 64);

  private final JComponent comp;
  
  public MyTextFieldUI(JComponent comp) {
    if (comp == null) {
      throw new IllegalArgumentException(
        "comp should not be null.");
    }
    this.comp = comp;
  }
  
  public static ComponentUI createUI(JComponent c) {
    return new MyTextFieldUI(c);
  }

  protected void paintBackground(Graphics g) {
    super.paintBackground(g);
    Dimension size = comp.getSize();
    MyLookAndFeelUtil.gradationFill(
        GRADATION_START, GRADATION_END,
        0, 0, size.width, size.height,
        g);
  }
}

[プログラム: MyButtonUI.java]

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicButtonUI;

public class MyButtonUI extends BasicButtonUI {
  private static final Color GRADATION_START =
      new Color(255, 255, 255, 0);
  private static final Color GRADATION_END =
      new Color(0, 0, 0, 64);

  public static ComponentUI createUI(JComponent c) {
    return new MyButtonUI();
  }

  public void paint(Graphics g, JComponent c) {
    super.paint(g, c);
    MyLookAndFeelUtil.gradationFill(
        GRADATION_START, GRADATION_END,
        0, 0, c.getWidth(), c.getHeight(),
        g);
  }
}

[プログラム: MyLookAndFeelUtil.java]

import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Rectangle;

public class MyLookAndFeelUtil {
  public static void gradationFill(
      Color c1, Color c2,
      int x, int y, int width, int height,
      Graphics g) {
    Paint p = new GradientPaint(
      (float)x, (float)y, c1,
      (float)x, (float)(y + height), c2);
    fill(p, x, y, width, height, g);
  }

  public static void fill(
      Paint p,
      int x, int y, int width, int height,
      Graphics g) {
    Graphics2D g2d = (Graphics2D)g;
    g2d.setPaint(p);
    g2d.fill(new Rectangle(x, y, width, height));
  }
}

[プログラム: MyLookAndFeel.java]

import javax.swing.UIDefaults;
import javax.swing.plaf.basic.BasicLookAndFeel;

public class MyLookAndFeel extends BasicLookAndFeel {
  public String getDescription() {
    return "This is My Look & Feel.";
  }

  public String getID() {
    return "MyLookAndFeel";
  }

  public String getName() {
    return "My Look & Feel";
  }

  public boolean isNativeLookAndFeel() {
    return false;
  }

  public boolean isSupportedLookAndFeel() {
    return true;
  }

  public UIDefaults getDefaults() {
    UIDefaults uiDefaults = super.getDefaults();
    
    uiDefaults.putDefaults(new Object[] {
      "ButtonUI", "MyButtonUI",
      "TextFieldUI", "MyTextFieldUI",
    });
    
    return uiDefaults;
  }
}

[実行結果]

MetallicLook&Feel

4. ほろ酔い Look & Feel

基本的にはこの要領で各コンポーネントに対応した UI クラスを用意し、UIDefaults に登録していけば独自 Look & Feel を作成していくことができる。

ちなみに、上記の MyTextFieldUI と MyButtonUI の static フィールドを次のように書き換えると、メタリック風だった Look & Feel をほろ酔い風のものにすることもできる。

  GRADATION_START = new Color(255, 0, 0, 0);

[動作結果]

HoroyoiLook&Feel

ということで、今回は Look & Feel の作り方でした。

このエントリーをはてなブックマークに追加 このエントリーを含むはてなブックマーク livedoorクリップ del.icio.us テクノラティ検索
lalha_java at 02:32 │Comments(2)TrackBack(0)

トラックバックURL

この記事へのコメント

1. Posted by 悩む人   2007年10月12日 11:41
「2. Look & Feel 作成の下準備」のLookAndFeelTest.javaと、「3. メタリックな Look & Feel の作成 」のjavaをローカルにコピーさせていただき、実行してみましたが、コンパイルエラーとなりました。

UIDefaults.getUI() failed: no ComponentUI class for: javax.swing.JTextField[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.0,border=,flags=0,maximumSize=,minimumSize=,preferredSize=,caretColor=,disabledTextColor=,editable=true,margin=,selectedTextColor=,selectionColor=,columns=0,columnWidth=0,command=,horizontalAlignment=CENTER]
java.lang.Error
−以降略−

<環境>
WindowsXP
java 1.5.0_10

以上、ご報告まで。。

2. Posted by 通りすがり   2008年08月11日 18:52
>>2
私も同じエラーではまってしまいました。
コメント日付がだいぶ前のものですが一応レスしておきます。

恐らく、ソースをコピペした際にパッケージをきって格納していませんでしたか?

uiDefaults.putDefaults(new Object[] { "ButtonUI", "MyButtonUI",
"TextFieldUI", "MyTextFieldUI", });

この部分の指定をきちんとパッケージから書いてあげれば大丈夫だと思います。

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔