WisdomSoft - for your serial experiences.

5.5 Swingの軽量コンポーネント

Swing におけるコンポーネントは、AWT の Component クラスから派生した JComponent から派生しています。Swing のコンポーネントは全てが軽量コンポーネントであり、Java によって描画されています。

5.5.1 JCmoponent クラス

5.4 コンテンツペイン コード1」では、Component クラスを継承した独自の軽量コンポーネントをウィンドウに追加しましたが、Component クラスは AWT に分類されるもので、この時点では Swing アーキテクチャをサポートしていません。Swing を採用するコンポーネントは必ず javax.swing.JComopnent クラスを継承しなければなりません。

javax.swing.JComopnent クラス
java.lang.Object
  |
  +--java.awt.Component
        |
        +--java.awt.Container
              |
              +--javax.swing.JComponent
public abstract class JComponent extends Container implements Serializable

JComponent クラス自体は抽象クラスなので、Swing コンポーネントはこのクラスを継承して作成します。当然、すべての標準 Swing コンポーネントも、このクラスから派生しているため JComponent クラスを理解するということはきわめて重要なのです。

ひとつ重要なのは、JComponent クラスが Container を継承しているということです。Container は子コンポーネントを含むことができるため、事実上 Swing コンポーネントは、軽量コンテナであることを意味しています。

JComponent クラスは Swing コンポーネント全体に共通する基本的なメソッドをサポートしています。AWT では、コンポーネントの適切なサイズを取得する getPreferredSize() メソッドはありましたが、適切なサイズを設定する setPreferredSize() というメソッドは存在しません。そのため、コンポーネントの適切なサイズを新たに設定するには、コンポーネントを継承してメソッドをオーバーライドするしかありませんでした。しかし、JComponent クラスでは setPreferredSize() メソッドを追加しているため、全ての Swing コンポーネントは適切なサイズをインスタンスごとに設定することが可能になっています。

JComponent クラス setPreferredSize() メソッド
public void setPreferredSize(Dimension preferredSize)

また、JComponent クラスは軽量コンポーネントなので、デフォルトでは背景を描画しません。そこで、背景を透明にするか不透明にするかを表す新しい設定値が追加されています。背景を透明にするかどうかを設定するには setOpaque() メソッドを、取得するには isOpaque() メソッドを使います。

JComponent クラス setOpaque() メソッド
public void setOpaque(boolean isOpaque)
JComponent クラス isOpaque() メソッド
public boolean isOpaque()

isOpaque() メソッドが返す値が true であれば、コンポーネントは不透明である、すなわち軽量コンポーネントの全てのピクセルを上書きすることを表しています。この値をどのように利用するかはサブクラスに委ねられています。例えば、常に不透明なコンポーネントであれば isOpaque() メソッドをオーバーライドして、常に true を返すようにプログラムしなければなりません。

コード
import javax.swing.*;
import java.awt.*;

public class Test {
	public static void main(String args[]) {
		LabelEx label = new LabelEx("Kitty on your lap");
		label.setFont(new Font("Serif" , Font.PLAIN , 20));
		label.setForeground(Color.BLUE);
		label.setBackground(Color.WHITE);
		label.setOpaque(true);

		JFrame win = new JFrame();
		win.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		win.setBounds(10 , 10 , 400 , 300);
		win.getContentPane().add(label);
		win.show();
	}
}

class LabelEx extends JComponent {
	private String label;
	public LabelEx(String label) { this.label = label; }

	public void paint(Graphics g) {
		if (isOpaque()) {
			Color color = g.getColor();
			g.setColor(getBackground());
			g.fillRect(0 , 0 , getWidth() , getHeight());
			g.setColor(color);
		}
		if (label != null) {
			FontMetrics fm = getFontMetrics(getFont());
			g.drawString(label ,
				getWidth() / 2 -  fm.stringWidth(this.label) / 2 ,
				getHeight() / 2 + fm.getDescent()
			);
		}
	}
}
実行結果
コード1 実行結果

コード1は、JComponent クラスを継承する LabelEx クラスを定義しています。このコンポーネントは Swing コンポーネントのスーパークラスである JComponent を継承しているため、Swing のルールが適用されています。LabelEx クラスは、isOpaque() が true である場合はコンポーネントが不透明であることを意味するため、背景色でコンポーネント全体を塗りつぶします。透明に関する設定は setOpaque() メソッドを用いて外部から設定することができます。このプログラムは、背景色を白に設定した後 setOpaque() メソッドで不透明なコンポーネントを指定しています。