最終更新日:

Chapter10
ソフトウエアの部品を使う
Eclipse(Indigo)編

ダイアログボックスでは、ボタンやテキスト枠、ドロップダウンリストを使って、ユーザーの操作を受け付けるようになっています。こうした素材はJavaのシステムで用意されているので、それを決まりに従って利用するだけで、自分で作ったプログラムでボタンなどが使えます。こうしたソフトウエアの部品を総称して「コンポーネント」と呼ばれます。

10-1 プロジェクトを用意する

この章のプログラムを作成するためのプロジェクトを新たに用意します。そこにアプリケーションを追加します。「新規プロジェクト」のウインドウでは「Javaプロジェクト」を選択し、プロジェクト名は、SwingGUIとします。

プロジェクトは「SwingGUI」という名前にする

プロジェクトを作成したら、そのプロジェクトの中に新たなクラスを定義します。この章でのアプリケーションは、ウインドウに表示します。ウインドウは、Javaのライブラリの中で「JFrame」という名前のクラスで定義されています。そのウインドウに対して「中身を追加する」という感じでプログラムを進めます。これから作るクラスは「UseComponents」という名前にします。パッケージには「swinggui」とプロジェクト名と同じものを指定しますが、加えてスーパークラスというところに「javax.swing.JFrame」とキータイプします。これにより、ウインドウを実現する機能を持ったJFrameをさらに継承して拡張したUseComponentsを作るということになります。「javax.swing」はクラスを分類するためのプレフィックスで、クラス名がJFrameです。「public static void main(String[] args)」のチェックボックスはチェックは入れまん。

主要なクラスは「UseComponents」という名前にする

プロジェクトには、もう1つのクラス「Starter」を作ってください。同様に、プロジェクトを選択した状態で、新規にクラスを作ります。パッケージは「swinggui」、クラス名は「Starter」、「public static void main(String[] args)」のチェックボックスはチェックをオンにして作成します。

起動用のクラスを作成する

このStarterクラスは、UseComponentsクラスで定義したウインドウを、実際のプログラムの中で稼働させるという意味があります。外部から「実行する」という処理要求を受け付ける「static void main」というメソッドがあります。その中で、UseComponentsのインスタンスを生成するだけですが、起動の呼び出しと、実際の機能を別々のクラスで記述することにします。Starterクラスは、以下のように、UseComponentsというクラス名の前にnewを付けた記述を書いて、インスタンス生成が起動時になされるようにしておきます。

package swinggui;

public class Starter {
	public static void main( String[] args )	{
		new UseComponents();
	}
}

とりあえず、ここまでで、一度実行をしておきましょう。エラーが出ないで実行できることを確認します。パッケージ・エクスプローラで見えているStarter.javaの項目を右ボタンでクリックして、メニューから「実行」の「Javaアプリケーション」を選択します。一度選択すれば、ツールバーにある緑色の円に▷マークのある「実行」ボタンで、Starterが起動できます。

StarterをJavaアプリケーションとして実行する

この状態だと、ウインドウ自体は存在しますが、きちんと見えるように大きさなどが設定されていません。画面左上に、タイトルバーの残骸のようなものがあるのが、UseComponentsクラスのインスタンスです。一度、閉じるボタン(×ボタン)をクリックして、ウインドウを閉じておいてください。

10-2 ウインドウにコンポーネントを配置する

Javaは単にプログラムとしてデータの処理ができるだけでなく、ボタンやテキストボックスなどが利用できるようになっています。さまざまな機能を提供するソフトウエア部分は「ライブラリ」などと呼ばれています。つまりJavaが利用できる状態で用意されてるライブラリに、ボタンなどを扱う機能があるというわけです。ライブラリは一般的な言い方で、Javaでは具体的にはパッケージと呼んでいます。そして、たとえばボタンは1つのクラスとしてパッケージの中で定義されています。それはソフトウエアを構成する部品の様に利用できるわけです。ボタンをいちいち自分で作るわけではなく、クラスとしてすでに用意されているボタンを使ってプログラムを作成するわけです。

コンポーネントとAWTやSwing

Javaのパッケージの1つにAWT(Abstract Windowing Toolkit)というものがあります。これは、Javaの初期の頃から存在するパッケージで、ウインドウ表示やボタンなどの基本的な画面処理を行なう機能がまとまったライブラリです。現在のJavaもAWTが基礎になっています。

このAWTの機能をプログラムで使うときに、このパッケージを使うことをプログラムの最初に宣言しておく必要があります。それが以下の部分の記述です。

import java.awt.*;

たとえば、AWTの中でボタンはButtonというクラスで定義されていますが、パッケージ名を含んだ正式な名前は、java.awt.Buttonなのです。プログラム中にこのように正式名称でプログラムに書いてもよいのですが、長くなってみづらいので、通常はButtonだけをプログラム中に書き、importステートメントで指定した名前で*をワイルドカードと解釈して、java.awtで始まるすべてのクラスを利用できるようになっています。

AWTは機能的には最低限のものだけでした。そこで、Java 1.1の時代に付加パッケージとして、より高機能なSwingというものが作られました。Swingは、JFC(Java Foundation Components)というライブラリ群の1つですが、多彩なユーザインタフェースを構築できる点で華やかな存在であると言っていいでしょう。このSwingはJava2以降で標準ライブラリとなっています。

Swingを利用するには、やはりSwingのパッケージをプログラムで利用するということを宣言しなければなりません。それが、以下の部分に相当します。

import javax.swing.*;

コンポーネントを使用する

AWTとSwingにあるユーザーインタフェースのためのコンポーネントの代表的なものを、表にまとめました。どのようなクラスがあるのかということがまず重要で、ボタンとしてのButtonや、複数行のテキストはTextAreaだというあたりを確認してください。ちなみに、AWTはどちらかといえば必要最低限のコンポーネントに限られています。たとえば、タブやスライダー、HTMLテキスト編集など多彩な部品を使いたい場合には、Swingを使うことになるでしょう。

AWTやSwingのコンポーネント
種類AWTでのクラス名Swingでのクラス名
ボタンButtonJButton
JToggleButton
チェックボックスCheckBoxJCheckBox
オプションボタンCheckBoxJRadioButton
オプションボタン管理CheckBoxGroupButtonGroup
1行のテキストボックスTextFieldJTextField
JPasswordField
複数行のテキストボックスTextAreaJTextArea
JEditorPane
文字列表示LabelJLabel
JTextPane
ドロップダウンリストChoiceJComboBox
選択リストListJList
テーブルJTable
ツリー表示JTree
スクロールバーScrollbarJScrollBar
スライダJSlider
プログレスバーJProgressBar

ウインドウにボタンを配置する

こうしたクラスを利用して、ウインドウにそれらが表示されるようなプログラムを作ってみましょう。まずは、以下のようにプログラムを入力して実行してみてください。プログラムの内容はその後で説明をします。

UseComponentsクラスにプログラムを入力し実行した
package swinggui;

import javax.swing.*;

public class UseComponents extends JFrame {
	private static final long serialVersionUID = 1L;

	JPanel panel = new JPanel();
	JButton button1 = new JButton( "BUTTON" );

	public UseComponents() {
		this.setBounds( 50, 100, 400, 250 );
		this.panel.add( this.button1 );
		this.setContentPane( this.panel );
		this.setVisible( true );
	}
}

入力できれば実行してみてください。もちろん、StarterクラスをJavaアプリケーションとして実行します。最初に1度実行すれば、ツールバーの実行ボタンで実行できます。画面上に、ウインドウが表示され、ボタンが1つ表示されているのを確認します。

プログラムの動作

ボタンを利用したいのであれば、SwingのパッケージにJButtonクラスが定義されているので、それを利用します。クラスは設計図であって、ボタンそのものではありません。そこで、ボタンを実際に使うときには、newキーワードを使ってJButtonクラスのインスタンスを生成しなければなりません。そのときに使われる特別なメソッドがコンストラクタなのですが、むしろ既に用意されているクラスを使う場合には、コンストラクタをどのように書くのかということよりもどのように使うかということが問題になるでしょう。

JButtonには生成のためのいくつかの方法が用意されています。「new JButton()」として、単に新たにJButtonクラスのインスタンスを作成することができます。また、ここでのプログラムのように、引数を取る事もできます。そうすると、その引数がボタン名となります。そしてJButtonクラスのインスタンスへの参照を戻すので、一般にはこれを何かの変数に代入しておきます(その値を特に使わない場合には変数に代入しなくてもかまいません)。このプログラムでは、UseComponentsクラスのメンバ変数として、生成したボタンへの参照を記録する変数button1を用意していますが、同時にインスタンス化も行っています。

JButton button1 = new JButton( "BUTTON" );

これで、UseComponentsクラス内では、button1という変数が、生成したJButtonのインスタンスを参照することになります。なお、インスタンス変数の確保は、UseComponentsのインスタンス化のときに行なわれます。結果的にそのときにJButtonのインスタンスも生成されて、変数button1への参照の代入が行われます。UseComponentsがインスタンス化されたときに、すでにJButtonのインスタンスも作られて利用可能になると考えればよいでしょう。

JButtonクラスには、ボタン名を設定するメソッドとして、setTextが用意されています。UseComponetsクラスのコンストラクタの中に、コメント(//)されている行があります。当初は「BUTTON」という名前のボタンですが、コメントにしている//を削除して有効な命令にしてから実行すると「ボタン」という名前のボタンに変わる事を確認してください。ここの部分でボタンの名前を変更していることが分かるはずです。setTextの引数に指定した文字列を、ボタン名にします。以下の部分です。これで、button1変数が参照するJButtonクラスのインスタンスに対して、「ボタン」という名前を割り当てます。

button1.setText("ボタン");

いずれにしても、こうしたボタンやテキストボックスが、前に示したような非常に簡単なプログラムで作成できます。ボタンはコンストラクタで生成をして、必要に応じてメソッドを利用するだけで使えるようになるというわけです。これは、ソフトウェアの部品がJavaの実行環境で用意されていて、それを利用しているのだというイメージを思い浮かべてください。

ウインドウを表示する

UseComponentsクラスは、JFrameつまりSwingのウインドウのクラスを拡張して定義しているので、すでにこの時点でUseComponentsはウインドウとしての機能を持ちます。ただし、単に生成したウインドウは大きさがまったくなく、見えてもいません。そこで、最低限でも、大きさを設定し、見えるようにするという命令をウインドウに与えてやる必要があります。

どこでそれを行うのかというのは1つのやり方があるわけではありませんが、前のプログラムでは、UseCompoentsクラスのコンストラクタで行っています。Sterterクラスでnew UseComponentsを実行したときに、UseComponentsクラスのUseComponents()というコンストラクタが呼び出されます。そこで「自分自身に対して」大きさの設定と見えるようにするという設定をします。それらが、コンストラクタの以下の部分です。

this.setBounds( 50, 100, 400, 250 );
	:
this.setVisible( true );

いずれも「this」は自分自身、つまり生成されたUseComponentsクラスを示しています。このクラスはJFrameを継承しているので、JFrameの機能をすべて使えます。setBoundsやsetVisibleというメソッドは実はJFrameで使えるようになっているメソッドなのです。

setBoundsは、4つの引数を取っていますが、最初の2つが、ウインドウの左上の座標、後半の2つがウインドウのサイズです。単位は、画面上のドットと考えてください。画面の座標系は、数学の座標系とちょっと違って、左上が原点です。横軸(x軸)は右方向が正の数ですが、縦軸(y軸)は下方向が正の数と逆になります。setBoundsは、左上の座標と大きさをまとめて指定するものですがつまりはこれによって場所と大きさが設定されることになります。

setVisibleメソッドは、引数を1つ取って、それはboolean型です。trueなら表示、falseなら非表示です。

コンポーネントをウインドウに追加する

これまでの部分では、確かにボタンというものを管理するオブジェクトを生成はしていますが、それは「パソコン内のどこか」にあるに過ぎないわけです。それをウインドウの表示領域に組み込む必要があるのです。言い換えれば、そうした組み込み作業はプログラムで書く必要があります。

ウインドウにいきなり表示させることも不可能ではないのですが、いろいろな理由があって、ウインドウそのものは「描画領域」を持たないという仕組みになっています。ウインドウそのものに対して「描画領域」を準備しておき、その領域にボタンなどを配置するという間接的なことを行う必要があります。描画領域としては、原則はいろいろな仕組みを追加できますが、このサンプルプログラムでは、JPanelというクラスを利用します。JPanelは、名前のパネルにもあるように、ある意味、何も表示しない真っ白なパネルと考えてて下さい。JPanelのインスタンスを管理するメンバ変数を定義したときに、インスタンス化をしています。

JPanel panel = new JPanel();

そして、UseComponentsのコンストラクタにある以下の部分を見てください。画面に表示したいボタンを、パネルに配置します。それが、addメソッドです。この1行は「ボタンをパネルに追加する」と読み取ります。逆ではないです。そして、その次は、パネルをウインドウに組み込みます。ウインドウの表示領域は、setContentPaneメソッドで設定ができます。こうして、ウインドウ上にパネルがぴったり全域に張り付き、その上にボタンが表示されるというようになります。

panel.add( button1 );
this.setContentPane( panel );

10-3 いろいろなコンポーネントを使ってみる

ボタンだけでは寂しいので、もっといろいろなコンポーネントを配置してみます。以下のように、UseComponentsクラスにプログラムを追加してください。新たに登場するのは、JCheckBoxクラス、JTextAreaクラス、JComboBoxクラスです。それぞれ、名前の通りのコンポーネントです。いろいろなメソッドが実際には使えますが、このプログラムではそれぞれのインスタンスに対してsetTextメソッドしか使っていません。ここまでに説明して来たボタンと同様に考えれば、プログラムはすぐに分かるでしょう。

さらにプログラムを入力したUseComponentsクラス
package swinggui;

import javax.swing.JFrame;		//この行はなくてもよい
import javax.swing.*;

public class UseComponents extends JFrame {
	private static final long serialVersionUID = 1L;

	JPanel panel = new JPanel();
	JButton button1 = new JButton( "BUTTON" );
	JCheckBox checkbox1 = new JCheckBox();
	JTextArea textarea1 = new JTextArea();
	JComboBox<String> combobox1 = new JComboBoxx<String>();

	public UseComponents() {
		this.setBounds( 50, 100, 400, 250 );

		this.button1.setText( "ボタン" );
		panel.add( this.button1 );

		this.checkbox1.setText( "チェックボックス" );
		panel.add( this.checkbox1 );

		this.textarea1.setText( "テキストエリア¥nTextArea" );		//¥マークが間にあることに注意
		this.panel.add( this.textarea1 );

		this.panel.add( this.combobox1 );

		this.setContentPane( this.panel );
		this.setVisible( true );
	}
}

実際にプログラムをStarterから実行して、ウインドウにいくつかのコンポーネントが表示されることを確認します。また、チェックボックスがクリックによって切り替わったり、テキストフィールドにテキストを入力したりあるいは削除などの編集ができることも確認します。コンボボックスは、何も選択肢はありません。

実行結果

コンボボックスに選択肢を追加する

一覧から選択して使うコンポーネントとして、リストやコンボボックスがあります。コンボボックスは、ボタンなどと違って1つのテキストを表示するものではなく、代わりに選択肢をいくつか指定するのが通常です。UseComponentsにさらにプログラムを追加して、選択肢を出せるようにしてみます。「panel.add( combobox1 );」の前に、以下のように3行分を追加してみて、実行してください。ドロップダウンリストにaddItemメソッドに指定した文字列が選択肢として見えています。

combobox1.addItem("りんご");
this.combobox1.addItem("みかん");
this.combobox1.addItem("なし");
this.panel.add( this.combobox1 );
コンボボックスに選択肢が出るようにした

JComboBoxには、addItemというメソッドが用意されています。このメソッドの引数に指定した文字列がプルダウンメニューに登録されます。複数の項目をプルダウンメニューに入れたい場合には、何度かこのメソッドを使いますが、addItemで設定した順にプルダウンメニューでは一覧されます。

JComboBoxでは、選択した項目を取り出すのに、getSelectedItem()というメソッドを利用することができます。また、何番目の項目を選択したかを取り出すのに、getSelectedIndex()というメソッドを利用できます。いずれも、引数は指定しなくてもかまいません。

10-4 レイアウト機能について

AWTでは、コンポーネントをウィンドウに配置するときに利用できる機能として「レイアウト機能」を用意しています。ここまでに紹介しているプログラムで、単にボタンなどのコンポーネントをaddによる追加だけで何となく配置されていて、特に座標などを指定しなかった点について不思議だと感じているかもしれません。これは、レイアウト機能によって自動的に配置されているからです。

単に配置するだけなら、座標値を指定して配置するのと同じだし、そのほうが簡単だと思うかもしれません。しかしながら、Javaで作ったプログラムは、どんな環境で動かすことを目指しています。一方で動作環境上の微妙な違いが出てきて、意図しない結果にもつながります。たとえば、ボタンの幅は、WindowsとMac OS Xで違いがあるかもしれないのです。レイアウト機能をうまく使うと、そうした違いをあるある程度吸収する事が可能です。

また、あとで実例を示しますが、ウィンドウに表示したとき、ウィンドウのサイズ変更に対してコンポーネントの位置が追随するような動作まで可能になっています。アプリケーションとして作ったもので、ウィンドウに何かを表示する場合には、レイアウト機能を使うことで、何もしなくてもウィンドウのサイズ変更に追随できるようになるというメリットもあります。

レイアウト機能には、表のようにいくつかの種類があります。「レイアウト機能」の列の名前は、そのレイアウトの機能を提供するクラス名です。Javaの世界ではこうしたレイアウト機能がクラスとして定義されていて、プログラムの中で利用できます。

AWTで用意されているレイアウト機能
レイアウト機能特徴
BorderLayout表示領域の周辺にコンポーネントを配置できる。ウインドウの既定のレイアウト機能
CardLayoutページ切り替えができる表示領域
FlowLayoutコンポーネントを左から右、上から下へと順番に配置する
GridLayout行列に分割してそれぞれにコンポーネントを配置する
BridBagLayout行列に分割してそれぞれにコンポーネントを配置する。GridLayoutよりも柔軟に領域を設計できる

●FlowLayoutについて

JPanelは、FlowLayoutが既定のレイアウトになっています。何もしなければ、このレイアウトが採用されています。この場合、addした順序にコンポーネントが適当なサイズ(中身が概ね見えているサイズを求める)で並びます。また、ワープロのテキストのように、左から並べて幅を満たしてしまうと次はその下の位置に配置をします。左から右、上から下へ、「フロー」するレイアウトということです。プログラムを実行さ、ウインドウの右下の部分をドラッグするなどして、ウインドウの大きさをいろいろな大きさに変更してみましょう。すると、ウインドウの大きさに合わせて、コンポーネントのレイアウトの配置が変化します。

このような結果になることがよいか悪いかはさておいて、機能面ではおもしろいと感じられるのではないでしょうか。ウィンドウのサイズを変更したときの処置をプログラム内に何も記述していないにもかかわらず、ウィンドウのサイズ変更で、見え方がダイナミックに変わってしまいます。ちょうどテキストエディタで、テキストを折返しで表示しているような具合です。

実は、Javaを実行する環境によってボタンの大きさとかテキストフィールドの大きさは微妙に違っていたりするので、FlowLayoutだと、あるJava VMでは1行目に3つのコンポーネントがあったとしても、同じプログラムを別のJava VMで実行すると、1行目には4つのコンポーネントが配置されるかもしれないのです。その意味では、FlowLayoutは実用性に欠けると考えたくなるかもしれませんが、「なりゆき」で配置される手軽なレイアウト機能としてはそれなりに使い手はあります。

●レイアウト機能を使わないウインドウ

レイアウト機能を使わないウインドウを表示するために、現在のプロジェクトにUseComponentsNoLayoutクラスを定義してみます。クラスを追加するとともに、プログラムを次のように入力します。レイアウト機能の指定は、パネルに対してsetLayoutメソッドで行いますが、nullとは「何もなし」という意味で、レイアウト自体の機能をキャンセルしていると考えれば良いでしょう。レイアウト機能を使わない場合は、個々のコンポーネントのサイズを、プログラム上で指定する必要があります。

UseComponentsNoLayoutクラスを作成する
package swinggui;

import javax.swing.*;

public class UseComponentsNoLayout extends JFrame {
	private static final long serialVersionUID = 1L;

	JPanel panel = new JPanel();
	JButton button1 = new JButton( "BUTTON" );
	JCheckBox checkbox1 = new JCheckBox();
	JTextArea textarea1 = new JTextArea();
	JComboBox combobox1 = new JComboBox();

	public UseComponentsNoLayout() {
		this.setBounds( 50, 100, 400, 250 );
		this.panel.setLayout( null );

		this.button1.setBounds( 30, 10, 200, 20 );
		this.button1.setText( "ボタン" );
		this.panel.add( this.button1 );

		this.checkbox1.setBounds( 30, 40, 200, 20 );
		this.checkbox1.setText( "チェックボックス" );
		this.panel.add( this.checkbox1 );

		this.textarea1.setBounds( 30, 70, 300, 20 );
		this.textarea1.setText( "テキストエリア\nTextArea" );		//\マークが間にあることに注意
		this.panel.add( this.textarea1 );

		this.combobox1.setBounds( 30, 120, 200, 20 );
		this.combobox1.addItem( "りんご" );
		this.combobox1.addItem( "みかん" );
		this.combobox1.addItem( "なし" );
		this.panel.add( this.combobox1 );

		this.setContentPane( this.panel );
		this.setVisible( true );
	}
}

Starter.javaの方は、次のように変更します。UseComponentsクラスによるウインドウも表示されますが、まったく同じ場所に同じ大きさでUseComponentsNoLayoutクラスによるウインドウが表示されるようになるはずです。ウインドウをずらせば、両方のクラスによるウインドウが表示されていることが分かります。

package swinggui;

public class Starter {

	public static void main(String[] args) {
		// TODO 自動生成されたメソッド・スタブ
		new UseComponents();
		new UseComponentsNoLayout();
	}
}

実際にプログラムをStarterから実行して、指定した座標にコンポーネントが配置されていることを確認しましょう。setBoundsはウインドウと考え方は同じですが、ウインドウの中に配置するときには画面の左上が原点ではなく、ウインドウの表示領域の左上が原点となります。

実行結果

●BorderLayoutを使う

ウインドウでよく利用されているBorderLayoutについて紹介しましょう。一般的なアプリケーションでは、ウインドウ内にメニューバーやツールバーがありますが、そうしたプログラムを作る時にはBorderLayoutを使うと簡単にコンポーネントを配置できます。このレイアウト機能がどういうものなのかは説明をするより、動作を見る方が早いでしょうから、さっそくプログラムを作ります。まず、現在のプロジェクト「SwingGUI」に新たにクラスを作ります。プロジェクトの項目を選択した状態でクラスを新規に作成しますが、パッケージは「swinggui」、名前は「UseBorderLayout」、スーパークラスは「javax.swing.JFrame」とします。「public static void main(String args[])」のチェックは入れません。

新たにUseBorderLayoutクラスを作成する

UseBorderLayoutクラスには、以下のようにプログラムを入力します。

package swinggui;

import javax.swing.*;
import java.awt.*;

public class UseBorderLayout extends JFrame {
	private static final long serialVersionUID = 1L;

	JPanel panel = new JPanel();
	JButton button1 = new JButton( "ボタン1" );
	JButton button2 = new JButton( "ボタン2" );
	JButton button3 = new JButton( "ボタン3" );
	JButton button4 = new JButton( "ボタン4" );
	JButton button5 = new JButton( "ボタン5" );

	public UseBorderLayout()	{
		this.setBounds( 80, 120, 500, 300 );
		this.panel.setLayout( new BorderLayout() );
		this.setContentPane( this.panel );

		this.panel.add( this.button1, BorderLayout.NORTH );
		this.panel.add( this.button2, BorderLayout.SOUTH );
		this.panel.add( this.button3, BorderLayout.WEST );
		this.panel.add( this.button4, BorderLayout.EAST );
		this.panel.add( this.button5, BorderLayout.CENTER );

		this.setVisible( true );
	}
}
UseBorderLayoutクラスにプログラムを入力て実行した

一方、すでに存在するStarterクラスをそのまま流用します。以下のように、mainメソッドに、「new UserBorderLayout()」というのを増やしておきます。UseComponentsクラスを生成しているところはそのままでもかいませんが、以後、ウインドウが2つ出てきます。邪魔なら、「new UseComponents()」の行の最初に//を入れて、コメントとしてしまいます。

package swinggui;

public class Starter {

	public static void main(String[] args) {
		// TODO 自動生成されたメソッド・スタブ
		new UseComponents();
		new UseComponentsNoLayout();
		new UseBorderLayout();
	}

}

これでStarterクラスをJavaアプリケーションとして実行します。ウインドウの大きさを変更してみてください。極端な場合は別として、たとえばjButton2は高さが一定ですが、幅はウインドウ幅に追随されます。こうした大きさの調整が全自動で行われているのです。

実行して表示されたBorderLayoutWindowクラスのウインドウの大きさをいろいろと変えてみた

このような配置ができるのがBorderLayoutの特徴です。何と表現したらよいかは迷うところですが、ローマ数字の「Ⅱ」の文字のように、ウィンドウ内が区分けされていると言えばよいでしょうか。それぞれの区分け内では、ボタンがすっぽりと覆うように配置されています。

ウインドウの表示領域にJPanelを利用していますが、そのレイアウト機能に、setLayoutメソッドを利用して、BorderLayoutクラスのインスタンスを指定します。単に新たに生成してそれを指定すればいいので、まとめて記述しています。BorderLayoutクラス自体は、背後で動いてここで見ているような配置を行いますので、特にレイアウト機能に対してのプログラムを書く事ありません。

ウィンドウはボタンで埋められていますが、プログラム上ではボタンのサイズや位置などを指定していません。5つの領域それぞれに、東西南北と中心を意味する英単語が割り当てられていて、addメソッドでボタンを追加するときに、どの部分かを2つ目の引数で指定します。

BorderLayoutにコンポーネントを追加する

ところで、North部分の高さや、Eastの幅などは、うまくボタンの文字が隠れないようになっていると思いませんか? 実は、AWTやSwingのコンポーネントは「大きさ」という情報だけでなく「望ましい大きさ」「最小の大きさ」という情報も持っています。BorderLayoutでは、こうした情報を利用して、コンポーネントを配置します。たとえば、Northでは、そこに配置したコンポーネントの望ましい大きさの高さ分の領域を取り、横幅はこの場合だとウィンドウ幅いっぱいに取ります。Southも同様です。EastやWestは、望ましい大きさの幅の情報を使って、それらの領域の幅を決め、高さは、Northの下からSouthの上までを占めるように設定されます。そして、残りの場所をCenterが占めるという具合です。結果的にはうまくいっているように見えるのですが、その背後の機能について知っておいても損はないでしょう。

ここで、BorderLayout.NORTHのような記述がありますが、これは「定数」とも言えるものです。addメソッドの2つ目の記述用に用意されています。2つ目の記述で、たとえばその数値が1ならどこ、2なら別の場所…というようなルールがあってもいいのですが、そうすると、番号と場所の対応を覚えておかないといけなく、使いづらくなります。何らかの意味のある文字列で指定できれば、簡単に思い出せて使いやすくなるということで、こうした記述を使います。NORTHなどのキーワードがBorderLayoutクラスで定義されているということを意味しており、このため、スペルミスが合った場合は、実行前にコンパイルするときに検知してくれます。プログラミングをやりやすくする機能の1つと思ってください。

なお、この2つ目の引数は、以前は文字列を直接指定していました。「"Center"」などと指定をしていたのですが、ここで大文字と小文字の組み合わせなんて、すぐ忘れてしまい、毎度毎度調べていたりしました。しかしながら、そうした手法ではなく、ここで示したようにキーワードで指定する方法が後に用意されました。

●BorderLayoutの各パートには1つのコンポーネントのみ

BorderLayoutでは、同じパートに複数のコンポーネントをaddで追加しても、エラーは出ないで動いてくれます。しかしながら、最後に追加したコンポーネントだけしかウインドウには組み込まれていません。このように、BorderLayoutでは、5つある部分のそれぞれでは、最後にaddした1つのコンポーネントしか表示されないようになっています。

そうなるとなんて不便なんだと思うかもしれませんが、心配はいりません。BorderLayoutという機能を利用しながら、複数のコンポーネントを効果的に配置するということができます。そのポイントになるのはPanelあるいはJPanelというコンポーネントです。BorderLayoutの1つの部分に、まず、Panelだけを配置します。そして、配置したパネルの中に、ボタンをいくつか配置するということが行えます。コンポーネントを階層的に配置するものと思えばよいでしょう。こうしたやり方ができるので、かなり自由度は高くなってきます。

また、このように5つも分割している必要はないだろうと思うかもしれません。コンポーネントを追加していないパートは表示されないだけです。試しに、特定のパートへのaddの部分をコメントにして、addをしないでプログラムを実行してみてください。例えば、Southへのaddをやめると、ウィンドウの下端に貼り付く部分はなくなり、他のパートで埋められます。たとえば、ウィンドウいっぱいに1つのコンポーネントを配置したいのであれば、Centerだけに配置すれば、それですみます。その場合、他のパートは一切画面には登場しないのです。こうした使い方までを考えれば、BorderLayoutはいかに有用であるかは理解していただけるのではないかと思います。

練習問題

10-1:JComboBoxコンポーネントに、「日本」「アメリカ」「イギリス」「ドイツ」の4つの選択項目が出るようにする。そして、最初は「イギリス」が選択されているようにする。(ヒント、setSelectedItem("項目名") メソッドを使う)

10-2:BorderLayoutのウインドウを作り、以下のような方針で機能を組み込んでみること。

ところでメソッドはどう調べるか? 講義のトップページにあるリンク集からの見方を説明しましょう。