17-4:新しい LayoutManagerの定義

LayoutManagerインターフェイスと、 新しいレイアウトのポリシーの設計法について解説します。

・ JDKの java.awtパッケージに用意されたレイアウトのクラス以外に、 独自のポリシーを提供するクラスを作ることも可能です。 java.awtパッケージには、それらの新しいクラスを設計するための基本の機能を 提供する LayoutManager, LayoutManager2インターフェイスが用意されています。 また、Container(およびそのサブクラス)がレイアウトのポリシーとして 受け付けるのは、LayoutManagerをインプリメントしたオブジェクトに限られます。 (LayoutManger2 は LayoutManagerのサブクラスです。)
LayoutMangerインターフェイスは下記の5個のメソッドの実装を要求します。

このうち特に重要な働きを行うのが layoutContainer()メソッドです。 これはコンテナの doLayout()メソッドによって呼び出され、 実際のレイアウトの処理を行います。 この内容によってレイアウトの方針が決められるわけです。
LayoutManager2 インターフェイスは、上の5個の他にさらに以下の4個の メソッドの実装を要求します。 これらは LayoutManagerの機能を補助もしくは追加するためのものです。

実際の例を見てみましょう。 たとえば、 FlowLayoutに似たルールでコンポーネントを上から下に順に並べる TopdownLayout という新しいレイアウトのクラスを設計するとしましょう。 そのクラス定義は次のようになります。


/** 新しく設計されたレイアウトのポリシーのクラス TopdownLayout
    コンポーネントを上から下へ順に配置する */
import java.awt.*;
public class TopdownLayout implements LayoutManager {

    /** コンポーネント間の隙間のサイズ */
    int hgap;
    int vgap;

    /** コンストラクタ */
    public TopdownLayout() {
        this(5, 5);
    }

    /** コンストラクタ(コンポーネント間の間隔を指定) */
    public TopdownLayout( int hgap, int vgap ) {
        this.hgap = hgap;
        this.vgap = vgap;
    }

    /** LayoutManeger インターフェイスで予約されたメソッド 
        特に新しい処理は追加しない */
    public void addLayoutComponent( String name, Component comp ) {
    }

    /** LayoutManeger インターフェイスで予約されたメソッド 
        特に新しい処理は追加しない */
    public void removeLayoutComponent( Component comp ) {
    }

    /** 適切なサイズを計算して返すメソッド
        ここでは手を抜いて現在のサイズをそのまま返す */
    public Dimension preferredLayoutSize( Container cont ) {
         return new Dimension( cont.getSize().width,
                               cont.getSize().height );
    }

    /** 許される最小のサイズを計算して返すメソッド
        ここでは手を抜いて常に 1x1 のサイズを返す */
    public Dimension minimumLayoutSize( Container cont ) {
        return new Dimension( 1, 1 );
    }

    /** 内部のレイアウトを決定するメソッド */
    public void layoutContainer( Container cont ) {
        int xlimit = cont.getSize().width - hgap;
        int ylimit = cont.getSize().height - vgap;
        int x = hgap, y = vgap;
        int colw = 0;

        for (int i = 0 ; i < cont.getComponentCount() ; i++) {
            Component m = cont.getComponent(i);
            if ( m.isVisible() ) {
                Dimension d = m.getPreferredSize();
                int w = d.width;
                int h = d.height;
                m.setSize( w, h );
                if ( y + h <= ylimit ) {
                    m.setLocation( x, y );
                    colw = Math.max(colw, w);
                } else {
                    y = vgap;
                    x += hgap + colw;
                    if( x >= xlimit ) break;
                    colw = w;
                    m.setLocation( x, y );
                }
                y = y + h + vgap;
            }
        }
    }
}

このようなクラスが定義できたら、java.awtの既存のレイアウトのクラスと同様に 利用することができます。その取り扱いは全く同じです。


TopdownLayoutの例