プログラミング応用b 第11回 『GUIその1 (AWT/Swingによるウィンドウのデザインと生成)』


【コンポーネントとコンテナ】

 List 1とList 2は,ウィンドウを表示するだけでしたが,それだけではつまらないですね。
そこで,ボタンやポップアップメニューなどの“GUI部品”をウィンドウに追加してみましょう。
 なお,JavaではウィンドウやボタンのようにGUI上でユーザとやりとりをするための“部品”
を,コンポーネント(component)と呼びます。また,ウィンドウのように,他のコンポーネ
ントを含むことができる特殊なコンポーネントを,コンテナ(container)と言います。英語で
containerとは,“入れ物”という意味です。


【サンプルプログラム List 3】

 では,AWTを使って,Frame型ウィンドウというコンテナに,ボタンなどのコンポーネ
ントを“入れて”みましょう。List 3を見て下さい。このプログラムを実行すると,Fig.4
のように,ボタンをはじめとする多数のコンポーネントを配置したウィンドウが表示され
ます。List 3自体は,それほど複雑なプログラムではありませんね。このように,Javaで
は簡単にGUI部品をウィンドウに追加することができるのです。

List 3 AWTComponents.java



 では,List 3を見ていきましょう。List 3-<①>では,java.awtパッケージをインポートし
ています。List 2-<2>では大きさ横280pixel,縦250pixelのFrame型ウィンドウfを生成し
ています。次にいよいよ,このコンテナfにいろいろなコンポーネントを追加していきます。

【レイアウトマネージャによる配置】

 ここで,コンポーネントをコンテナに配置する方法を考えてみましょう。素直に考える
と,“コンテナ上の座標を指定して,その位置にコンポーネントを置ければよい”,とい
うことになるでしょう。実際,コンポーネントには

  setLocation( int x, int y )

というメソッドが用意されていて,コンポーネントをコンテナ上の位置( x, y )に置くことが
可能です。

 しかし,ことはそう単純ではないのです。Fig.4をよく見てみて下さい。Fig.4-(1)は MacOS X 10.3
での実行例,Fig.4-(2)はWindows XPでの実行例です。この2つの実行例を比較すると,
GUI部品の大きさや形が,プラットフォームによって異なることがわかります。たとえば,
同じボタンにしても,MacOS Xのボタンの方が,Windows XPのボタンよりも横長です。
また,Fig.1の例からもわかるとおり,同じ大きさのFrame型/JFrame型ウィンドウでも,
ボーダの有無によって,実際にコンポーネントを配置できる領域の大きさが異なったりす
るわけです。



 このように,コンポーネント(ボタンなど)の外形は,プラットフォームによって異なります。

そのため,異なるプラットホームで同じ様に動作することを理念とするJavaにおいては,
コンポーネントを使うとき,単純にコンテナ上の具体的な座標を指定してコンポーネント
を配置するのはあまり良い方法とは言えないのです。

 たとえば,Windows XP上でボタンを綺麗に配置したつもりでも,同じプログラムをMacOS X
上で動かしたときには,ボタンどうしが重なるなどしてレイアウトが崩れてしまう可能性が
あるわけです。逆に,MacOS Xで綺麗にボタンを配置したつもりでも,Windows XPでは,
ボタンの一部がボーダに隠されてしまうことも起こりえます。

 そこで,通常のJavaプログラミングでは,コンポーネントをコンテナに配置するときに,
配置位置の座標を具体的に指定することはしません。そのかわり,レイアウトマネージャ
という機能を使います。

 Javaには,それぞれ異なったコンポーネントの配置方針を持つレイアウトマネージャが,
標準で数種類用意されています。プログラマは,まず,使用したいレイアウトマネージャ
を選んで,コンテナにセットしておきます
。コンテナへのレイアウトマネージャのセット
は,コンテナに用意されている setLayout( ) メソッドを使います。

 そしてプログラマは,コンテナに用意されている add( ) メソッドで,コンテナにコンポー
ネントを“追加”するだけ
です。そして,追加されたコンポーネントの配置は,コンテナに
セットされたレイアウトマネージャが実行する
のです。レイアウトマネージャは自分のレイ
アウト指針に基づいて,(実行プラットフォームの事情を配慮しながら)コンポーネントを自
動的に綺麗に配置してくれます。

 List 3は,レイアウトマネージャを使用してコンポーネントを配置しています。そのおか
げで,Fig.4に示すように,異なるプラットフォームでも同じようにコンポーネントを綺麗
に配置できるのです。

 コンテナにはデフォルトのレイアウトマネージャが用意されています。Frame,JFrame,
Window,JWindow,Dialog,JDialogのデフォルトレイアウトマネージャは,ボーダレイ
アウト(BorderLayout)
と呼ばれるものです。しかし,List 3では説明の都合上,直感的にわ
かりやすいレイアウトマネージャであるフローレイアウト(FlowLayout)を使っています。
コンテナfにFlowLayoutを設定している部分が,List 3-<3>の

  f.setLayout( new FlowLayout( ) );

という部分です。フローレイアウトマネージャの効果については,他のレイアウトマネー
ジャと一緒に後ほどまた説明します。


【AWTの代表的なGUIコンポーネント】 

さて,コンテナにレイアウトマネージャを設定したので,次は様々なコンポーネントを
追加していく過程を見ていきましょう。


●ボタン (Button)

 まずは,コンポーネントの代表選手であるボタン(button)です。ボタンを表すAWT版の
クラスはButtonです。List 3-<4>の

  Button b1 = new Button("Button1");

という部分でボタンオブジェクトb1を生成しています。コンストラクタの実引数文字列は,
ボタンに表示されるキャプションになります。

 こうして生成したボタンb1をコンテナ(この場合はウィンドウ)に追加しているのが,List 3
-<5>の

  f.add( b1 );

という部分です。前述しましたが,コンテナのadd( )メソッドにより,コンポーネントをコンテナ
に追加します
。同様に,List 3-<6>で2個目のボタンb2を生成・追加しています。

 そうして生成・追加された2このボタンが,Fig.4-(1)(a)に示された2個のボタンです。
各ボタンのキャプションがそれぞれ,"Button1","Button2"になっていますね。各ボタ
ンを押してみる(マウスでクリックする)と,ちゃんとボタンが反応しますので確かめてみ
てください。

 このボタンの例のように,コンポーネントは,生成して,コンテナのadd( )メソッドで追加すれば
簡単に表示することができます。では,他のコンポーネントも追加していきましょう。

 

●ラベル (Label)

 ラベルは,文字列を表示するコンポーネントです(Fig.4-(1)(b))。ラベルの文字列内容は,
ユーザは変更できません。ラベルを表すAWT版のクラスは,Labelです。List 3-<7>の

  Label l1 = new Label( "Label1" );

がラベルを生成している部分です。コンストラクタの実引数文字列がラベルのキャプション
内容の初期値になります。生成したラベルオブジェクトl1を追加しているのが,List 3-<8>
です。List 3-<9>ではもうひとつラベルを生成・追加しています。

●チェックボックス (Checkbox)

 チェックボックスは,チェックマークをつけることのできる矩形のコンポーネントです
(Fig.4-(1)(c))。チェックボックスを表すAWT版クラスはCheckboxです。
 List 3-<10>がチェックボックスを生成している部分です。コンストラクタの呼び出しは

  Checkbox( "Chack Box 1", true );

となっています。第1引数は,チェックボックスのキャプションです。第2引数は,このチェ
ックボックスがチェックされた状態(true)か,チェックされていない状態(false)かを指定し
ます。ここでは,チェックされた状態で生成していることになります。生成したチェックボ
ックスオブジェクトcb1をコンテナに追加しているのが,List 3-<11>です。

 同様に2個目のチェックボックスを生成しているのがList 3-<12>の部分です。この2個目
のチェックボックスcb2は,チェックされていない状態で生成されていることに注意してく
ださい。Fig.4-(1)(c)で1個目のチェックボックスはチェックされている状態,2個目のチェ
ックボックスはチェックされていない状態であることを確認してください。

 またFig.4の状態で,チェックボックスはすでにマウスクリックでチェックをつけたりはず
したりできるので試してみてください。また,両方のチェックボックスに同時にチェックを
つかられることも試してみてください。この,複数のチェックボックスに同時にチェックを
つけられる
ことが,次に紹介するラジオボタンとの大きな違いになっているのです。

●ラジオボタン (グループ化されたCheckbox)

 ラジオボタンは,ON/OFFの状態を持つ丸いボタンです(Fig.4-(1)(d))。ラジオボタン
は複数個が一組(グループ)になって使用されます。そして,そのグループのうち,ONに
できるラジオボタンは1個だけ
です。つまり,ラジオボタンは,複数の選択肢の中から1個
だけを選ばせたいときに使用するコンポーネントです
。一方,チェックボックスは,複数
の選択肢の中から0個以上を選択させるときに使用するコンポーネント
,というわけです。

 実際に,Fig.4-(1)(d)の2個ラジオボタンを使ってみましょう。この2個のラジオボタン
はグループになっています。初期状態では,第1のラジオボタン(左側の方)がONになって
いて,第2のラジオボタン(右側の方)がOFFになっていますね。ここで,第2のラジオボタ
ンをクリックすると,第2のラジオボタンがONになって,第1のラジオボタンが自動的に
OFFになります。実際に確かめてみてください。さらに,第1のラジオボタンをONにしな
おすと,第2のラジオボタンが自動的にOFFになります。

 ラジオボタンを表すAWT版クラスは,チェックボックスと同じCheckboxです。では,
ラジオボタンを作成する方法を見てみましょう。

 ラジオボタンはその性質上,グループ化する必要があります。そのため,まずはラジオ
ボタンのグループを表すCheckboxGroup型オブジェクトを生成しておきます(List 3-<13>)。
そして,Checkbox型オブジェクトを生成するときに,コンストラクタでこのグループを
指定します。List 3-<14>では
 
 Checkbox("Radio Box 1",true, cbg);

というように,第3引数でグループを指定しています。このようにすると,このチェック
ボックスは,指定されたグループに所属することになります。そして,グループに所属し
たチェックボックスは,自動的にラジオボタンとなる
のです。作成したラジオボタンをコ
ンテナに追加している部分が,List 3-<15>です。同様に,同じグループに属する2個目
のラジオボタンをOFF状態で生成し,コンテナに追加しているのがList 3-<16>の部分で
す。こうして,生成・追加された2個のラジオボタンが,Fig.4-(1)(d)で表示されている
2個のラジオボタンというわけです。

●リスト (List)

 リストは,複数の項目をスクロール可能な領域に並べて,ユーザに選択させるコンポー
ネントで,Fig.4-(1)(e)のような外観をしています。この状態でクリックによる項目選択
や項目のスクロールも可能ですので,確かめてみてください。リストは,多数の項目をで
きるだけ同時にユーザ見せて,そのうち1個(設定によっては2個以上)の項目を選択させた
いときに使います。
 リストを表すAWT版クラスは,Listです。List 3-<17>の

  List lst = new List( 3 );

がリストを生成しているところです。コンストラクタの引数は,同時に見せる項目数です。
この場合,3項目分を同時に見せられるようにリストコンポーネントの大きさが調整され
ます。ただし,スクロールバーがついている場合は,同時に見られる行数は,それより少
なくなることもあります。たとえば,Fig.4のリストコンポーネントでは,実際に見るこ
とのできる行数は2行になっています。また,行数を0とした場合,デフォルト値の4が使
われ,4行分を表示するように生成されることになります。

 リストの項目は,List 3-<18>のように,Listのadd( )メソッドによって項目を追加する
ようになっています。リストをコンテナfに追加しているのが,List 3-<19>です。

●ポップアップメニュー (Choice)

 ポップアップメニューは,複数の項目のうち1個だけをメニュー形式で選択させるコン
ポーネントです(Fig.4-(1)(f))。登録されている項目のうち,通常表示されているのは選
択されている項目だけで,クリックすることで選択可能な項目がメニュー形式で現れます。
Fig.4の状態で使用できますので,実際に項目を選択したりしてみてください。

 ポップアップメニューを表すAWT版クラスは,Choiceです。List 3-<20>がポップアッ
プメニューを生成している部分です。ポップアップメニューの項目は,Choiceのadd( )メ
ソッドで登録します
(List 3-<21>)。作成したポップアップメニューをコンテナfに追加し
ている部分がList 3-<22>です。

●テキストエリア (TextArea)

 テキストエリアとは,テキストを複数行にわたって編集できるコンポーネントです(Fig.4-(1)(g))。
Fig.4の状態で,テキストエリア内のテキストを実際に編集できますので,試してみてくだ
さい。テキストの行数や桁数が多くなると,自動的にスクロールバーが現れますので,スク
ロールバーでテキストをスクロールさせてみてください。

 テキストエリアを表すAWT版クラスは,TextAreaです。List 3-<23>では,テキストエ
リアのテキスト内容の初期値strを用意しています。List 3-<24>でテキストエリアを生成し
ていますが,コンストラクタの第1引数は,テキスト内容の初期値,第2引数は表示行数,
第3引数は表示桁数となっています。生成したテキストエリアをコンテナfに追加しているの
がList 3-<25>の部分です。

●テキストフィールド (TextField)

 テキストフィールドとは,1行だけのテキストを編集できるコンポーネントです(Fig.4-(1)(h))。
Fig.4の状態で,テキストを編集できますので,試してみてください。

 テキストフィールドを表すAWT版クラスは,TextFieldです。List 3-<26>では,テキス
トフィールドを生成しています。コンストラクタに渡した文字列は,テキスト内容の初期値
になります。List 3-<27>で,生成したテキストフィールドをコンテナfに追加しています。

そして,List 3-<29>でコンテナfを可視状態にすることで,Fig.4のように各種コンポー
ネントを含んだウィンドウが表示されるというわけです。

 


【レイアウトの方法】

 さて,ここでフローレイアウトの効果についてお話しし,他のレイアウトマネージャの
例としてグリッドレイアウトを紹介することにします。また,コンテナの大きさを自動調
整してくれるpack( )メソッドについて説明します。そして,コンポーネントの配置に非常
に有用な特殊なコンテナ,Panelについても紹介することにしましょう。

●フローレイアウト

 フローレイアウトのフロー(flow)とは,“流れ”という意味です。文字通り,フローレ
イアウトマネージャは,コンテナの中に,コンポーネントを“流し込む”ように配置しま
す。具体的には,add( )メソッドで追加した順番で,コンポーネントをコンテナ内の上から
下へ配置していきます。コンテナの幅に余裕がある場合には,同じ行に複数のコンポーネン
トを配置し,残りのコンポーネントは,その下の行以降へ同様に配置されていきます。行内
のコンポーネントは,(デフォルトでは)中央にそろえられます。

 Fig.4を見ると,List 3でadd( )メソッドを使って追加された順番で,各コンポーネントが
ウィンドウの上から下に詰められていることがわかります。

 レイアウトマネージャは,基本的にコンテナの大きさが変更された場合,コンポーネント
を再配置します。フローレイアウトを例にその様子を見てみましょう。List 3を実行して,
Fig.4のようにウィンドウを表示させてください。そして,マウスでウィンドウのサイズを
変えてみてください。

 実際にウィンドウのサイズをいろいろ変えた例を,Fig.5-(1)〜(3)に示します。ウィンド
ウ(コンテナ)の大きさに合わせて,コンポーネントの再配置が実行されていることがわかり
ますね。Fig.5-(1)では,同じ行内のコンポーネントが左詰めでもなく右詰めでもなく,中央
揃えに配置されている様子がよくわかります。
 なお,ウィンドウの横幅は,各コンポーネントが十分表示できるまではせばめられますが
(Fig.5-(3)),それ以上はせばめられなくなります。



●グリッドレイアウト

 フローレイアウトは,プログラマが実際の配置にほとんど気を遣わなくていい分,便利
なのですが,それが逆に困った状態をひきおこすことがあります。たとえば,Fig.5-(1)で
は,2個あるチェックボックスが2行に分かれてしまってます。これでは,ユーザはこのソ
フトを使いにくいと思うことでしょう。
 そういった場合,他のレイアウトマネージャを使えばいいわけです。ここでは,ある程度
コンポーネントの配置を予測できるレイアウトマネージャの例として,グリッドレイアウト
を紹介しましょう。
 グリッドとは,“格子”のことです。グリッドレイアウトマネージャ(クラスはGridLayout)
は,コンポーネントを格子状に配置するレイアウトマネージャです。実際にグリッドレイアウ
トを使用した例が,List 4です。

List 4 GridTest.java


List 4-<①>でjava.awtパッケージをインポート,List 4-<2>,<3>で200pixel四方のウィ
ンドウを生成しています。そして,グリッドレイアウトマネージャをコンテナ(ウィンドウ)f
に設定している部分が,List 4-<4>です。GridLayoutのコンストラクタ呼び出しは

  GridLayout( 3, 2 )

となっていますが,これは3行2列の格子を作成することになります。List 4-<5>で5個のボ
タンを生成・追加し,List 4-<7>でウィンドウを表示しています。

 List 4の実行結果がFig.6です。3行2列の格子状にボタンが配置されていることがわかります。
デフォルトの状態では,追加された順番に,格子の左上を起点として,左から右,上から下へ
向かってコンポーネントが配置されます。ウィンドウの大きさにあわせて,ボタンの大きさが
調整されていることに注意してください。




●ウィンドウのパック

 ところで,List 3-<2>やList 4-<3>では,setSize( )メソッドを使ってウィンドウの大
きさを設定していました。しかし,前述したように,プラットフォームによってコンポー
ネントの外形が異なるなら,このようにあらかじめウィンドウの大きさを決めてしまうの
は,危険であるということになります。追加したコンポーネントが,ウィンドウの領域の
中に入りきらない可能性があるからです。

 そこで,登録されているコンポーネントの情報から,自動的にウィンドウの大きさを適
切なサイズに調整するメソッドpack( )が役に立ちます。
 List 3-<28>とList 4-<6>では,
  f.pack( );
というpack( )の呼び出し部分がコメントアウトされていますが,これを有効にしてList 3,
List 4を実行してみてください。修正したList 3とList 4の実行結果は,それぞれFig.7-(1),
Fig.7-(2)のようになります。



 フローレイアウトの場合(Fig.7-(1))は,pack( )メソッドが呼ばれると,すべてのコンポ
ーネントが1行に収まるようにウィンドウの大きさが自動調整されます。ウィンドウの大き
さを変えようとしてマウスで操作しても,横幅と高さはこれ以上せばめられません。
 また,グリッドレイアウトの場合(Fig.7-(2))は,pack( )メソッドが呼ばれると,指定さ
れた格子を保ったまま,ボタンが標準の大きさ・形になり,すべてのコンポーネントが収ま
るようにウィンドウの大きさが調整されます。ウィンドウの大きさを変えようとしてマウス
で操作しても,横幅と高さはこれ以上せばめられません。
 以上のように,ウィンドウをパックすることで,ウィンドウの大きさを気にすることなく,
コンポーネントを追加することが可能になります。ですので,
  (1)コンテナにレイアウトマネージャを設定する
  (2)コンテナにコンポーネントを追加する
  (3)最後にウィンドウをパックする
という手順は,ひとつの定石ですのでおぼえておいてください。

Javaには,フローレイアウトやグリッドレイアウトの他にも,便利なレイアウトマネージャが
いくつも用意されています
。自分で調べて使ってみてください。



次は,Swingのコンポーネントとレイアウトの仕方について解説します。

次に進む