Deep Side of Java〜Java 言語再入門 第4回 〜 アプレット、スレッド、AWT

レイアウトクラス






AWTの使い方

レイアウトクラス

一般にGUIツールキットでは、生成されたWidgetの位置を即値で指定することはない。なぜならば、ユーザがウィンドウサイズを変更したり、カスタマイズする可能性があるからである。ユーザが表示テキストを変更した時、さらにフォントサイズを変更した時などに、レイアウトが崩れてはまずい。

だからサイズや位置を即値で指定するのではなく、ウィンドウサイズと関連した、相対的な「並び方」を指定し、抽象的なかたちでレイアウトのための「戦略」を指定する。つまり、「戦略」をオブジェクト化して、子Widgetを持つContainer クラスのWidgetに与えると、そのレイアウト「戦略」に従って、ウィンドウサイズに合わせて適切なレイアウトを行う。これはデザインパターンの「Strategy」パターンである。

AWTではこのレイアウトのオブジェクトは、LayoutManager interface を装備したクラスである。最も一般的なContainer クラスである Panel クラスのデフォルトは FlowLayout クラスのオブジェクトが使われる。次のものがあるが、当然、LayoutManager interface が要求するインターフェイスを備えれば、自前で用意することもできる。

FlowLayout クラス

重ならないように、可能な限り左から右へ子Widgetを置いていき、置けなくなればその下に配置する。一番単純なレイアウト「戦略」である。



BorderLayout クラス

「Center」「North」「South」「East」「West」の5つの「区画」に、それぞれWidgetを置く。このレイアウトが一番実用的には使いでがある。



GridLayout クラス

指定の行数/列数を持つ「グリッド」の中に、行列位置を指定してWidgetをはめ込む。ただし、すべてのグリッドは同じ大きさであり、複雑なことはできない。それをするには...



GridBagLayout クラス

を使う。「グリッド」の中にはめ込むことでは GridLayout と同じであるが、細かいレイアウトを指定するためのデータのオブジェクトとして、GridBagConstraints クラスがあり、これを使って各グリッドの細かい指定を行う。



BoxLayout クラス

これは JDK 1.2 で Swing と共に追加されたレイアウトクラスで、javax.swing パッケージにある。なぜか単純な縦配置/横配置がなかったため、それまではよく自前でそういうレイアウトクラスを定義して使っていたが、ようやく追加された。



また、GridBagLayout については、やや判りにくい。そこで、GridBagLayout が完璧に理解できるようなアプレットを作成した。これを見て遊んで欲しい。

つまり、これらのレイアウトクラスは、生成された各Widgetのサイズを計算し、それらのサイズを具体的なContainer クラスのサイズやウィンドウのサイズとの関係で、どう配置するのかを決定するのである。

また、Component クラスには、実は3つのサイズがあり、これらは混乱しやすい。整理すると次のような関係にある。

void setSize(Dimension), Dimension getSize()
これらはそのWidgetの実表示サイズである。つまり、setSize() すれば大きさを変更でき、getSize() すれば現在の表示の大きさを取得できる。しかし、この「大きさ」はレイアウトマネージャーの関知する所ではない。つまり、レイアウトマネージャーはまったくこの値を見ずに、レイアウトを実行する。そのため、setSize() で大きさを変更したとしても、ウィンドウ全体のサイズを変更すれば、サイズ変更したWidgetであっても、サイズが元に戻ってしまうという、なかなか意外な動作をする。

Dimension getPreferredSize()
これが多くのレイアウトマネージャが、そのWidgetのサイズであると認識する「大きさ」である。また、このComponent クラスのメソッドは、取得メソッドだけで、値をセットするメソッドが存在しない。それゆえ、サイズ変更をしてもちゃんとそれがレイアウトに反映するようにするためには、結論としてこのメソッドを上書きする必要がある。

Dimension getMinimumSize()
GridLayout, GridBagLayout の2つのレイアウトマネージャと、Container のレイアウトでは、最後の「最小サイズ」を見る。ちゃんと変更サイズがレイアウトに反映するようにするには、getPreferredSize, getMinimumSize の2つのメソッドを上書きする必要がある。

「サイズ変更に強い」Widgetの定義は次のようにする。

class MyButton extends Button {
     Dimension size;    /* 内部で与えられたサイズを保持 */
     MyButton( ) {  }
     MyButton( String s ) { super(s); } /* ラベルをセット */
     public void setSize( Dimension d ) {  /* サイズを変更する時には */
          size = d;     /* そのサイズを取っておく */
          super.setSize( d );
     }
     public Dimension getPreferredSize( ) { /* レイアウトマネージャが使う */
          if( size == null ) {     /* 最初はオリジナルのサイズをセット */
               size = super.getPreferredSize();
          }
          return size;
     }
     public Dimension getMinimumSize( ) {
          return getPreferredSize(); /* すべて getPreferredSize に任せる */
     }
}



copyright by K.Sugiura, 1996-2006