第8週:GUIを利用したアプレット

今週はGUIを使ったプログラムの作り方を学習します。GUI(Graphical User Interface)とは、ユーザーとプログラムとが視覚的なシンボルを通してコミュニケーションをとる方法のことをいいます。たとえばマウスでクリックするために配置されるボタンなどがそれにあたります。GUIを用いることで、ユーザーに対してわかりやすく親切なインターフェイスを提供することができます。

8.1 ボタンを用いたアプレット
8.2 newという命令と、クラスの「実体」について
8.3 チョイス・ボタンを用いたアプレット

8.1 ボタンを用いたアプレット

まず最初にGUIを用いたプログラムの例として、「ボタン」を用いた次のようなアプレットを作成します。

このアプレットは「On」と「Off」の二つのボタンを持っています。「On」のボタンをマウスでクリックするとSFCという文字が表示されます。「Off」の方のボタンをクリックするとSFCが消えます。

→ このプログラムの実行結果

このアプレットは以下のソースコードによって実現されます。とくにボタンの部分の記述に注目しながら、ソースコードをながめてみましょう。

/**
 * 第8週 GUIを用いたアプレット
 * On/Offの二つのボタンによりSFCの文字を表示/非表示する
 **/
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;

public class On_Off extends Applet implements ActionListener{
	
	boolean SFC;	// アプレットの2種類の状態(文字列の表示/非表示)を記憶する変数
	
	// initメソッド:アプレットの初期化を行う	
	public void init(){
	
		// 2つのボタンを用意する
		Button on = new Button("On");	// "On"のボタン
		Button off = new Button("Off"); // "Off"のボタン
		
		// "On"のボタンがアプレットのインターフェイスとして機能するための準備をする
		on.setActionCommand("ON");	// このボタンが押されたときに発生するイベントの
					       // コマンド名を「ON」と定める
		on.addActionListener(this);    // このボタンの上で発生したイベントのリスナーは
					       // アプレット自身であると定める
		add(on);			// アプレット本体の上にボタンを貼り付ける
		
		// "Off"のボタンがアプレットのインターフェイスとして機能するための準備をする
		off.setActionCommand("OFF");    // このボタンが押されたときに発生するイベントの
					        // コマンド名を「OFF」と定める
		off.addActionListener(this);	// このボタンの上で発生したイベントのリスナーは
					        // アプレット自身であると定める
		add(off);			// アプレット本体の上にボタンを貼り付ける
		
		// アプレットの初期状態を「非表示」の状態にしておく
		SFC = false;
	
	}
	
	
	// actionPerformedメソッド:ボタンが押されたときに発生するイベントの処理を行う
	public void actionPerformed( ActionEvent e ){
	
		// イベントのコマンド名を受け取る
		String command = e.getActionCommand();
		
		// コマンド名を手がかりに押されたボタンを判別
		// 押されたボタンに応じてアプレットの状態を決定する
		if (command.equals("ON")){	// コマンド名が「ON」→"On"ボタンが押された場合
			SFC = true;	        // アプレットの状態を「表示」に設定する
		}
		else if(command.equals("OFF")){ //コマンド名が「OFF」→"Off"ボタンが押された場合
			SFC = false;	         // アプレットの状態を「非表示」に設定する
		}
		
		// 再描画を行う
		repaint();
	}
	
	
	// paintメソッド:アプレット本体を表示する
	public void paint(Graphics g){
	
		// アプレットの状態が「表示」の場合のみ、文字列「SFC」を表示する
		if (SFC == true){
			g.drawString("SFC", 50, 50);
		}
	}
	
}

GUIを実現するために必要なクラス群はすべて「java.awt」以下にパッケージされています。従って、必ず

import java.awt.*;

というimport文を書いておきます。

つぎに、クラス名の宣言に続いてリスナークラスのimplementsが宣言されています。

implements ActionListener

ボタンがクリックされたときに発生するイベントはActionEventです。ここでimplementsされるActionListenerは、ActionEventが発生したときに呼び出されるリスナーメソッドを実装したリスナークラスです。

クラス名を宣言した後には、いつも通り複数のメソッドにまたがって利用される変数を宣言しておきます。今回はアプレットの2通りの状態(「表示」と「非表示」)を憶えておくためのboolean型の変数SFCを一つだけ用意しています。

initメソッドの中には大きく分けて次の3つの処理が記述されています。

一般的にGUIを構成するボタンなどのパーツ(これをGUIパーツと呼ぶ)は、プログラムの初期化の際に用意しておきます。従ってアプレットの場合には、initメソッドの中で準備に必要なすべての記述を行ってしまうのです。

「2つのボタンの用意」は、プログラム中の次の部分にあたります。

// 2つのボタンを用意する
Button on = new Button("On");	// "On"のボタン
Button off = new Button("Off"); // "Off"のボタン

ボタンはButtonクラスにひな形が用意されています。利用する際には、一つ一つのボタンに対してButton型の変数を用意しておきます。次にnewという命令でボタンの実体を作成し、用意しておいた変数の中に代入します。この手順を一般化すると次のようになります。

Button b = new Button("ボタンの表面に表示する文字列");

上記のbは変数名なので、自由に名前を付けられます。newという命令の直後にはスペースを挟んで再びボタンのクラス名Buttonを記述して、直後に「("ボタンの表面に表示する文字列")」を続けます。この部分はJavaプログラミングを行う上で重要な要素を含んでいます。後ほど再び、それについて詳しく触れることにします。

次に「それぞれのボタンがインターフェイスとして機能するための準備」です。たとえばボタンonについて、次のような3行の記述がなされています。

// "On"のボタンがアプレットのインターフェイスとして機能するための準備をする
on.setActionCommand("ON");	// このボタンが押されたときに発生するイベントの
				// コマンド名を「ON」と定める
on.addActionListener(this);    // このボタンの上で発生したイベントのリスナーは
				// アプレット自身であると定める
add(on);			// アプレット本体の上にボタンを貼り付ける
最初の2行はいずれも「on.〜」と始まっています。onはButton型の変数ですから、これらはButtonクラスが持っているメソッドを利用する記述です。先に記述されているsetActionCommand("文字列")というメソッドは、ボタンがクリックされた時に発生するイベント(ActionEvent)の「コマンド名」を設定するものです。この「コマンド名」は一つ一つのボタンについて設定しておくものです。そうすることで、発生したActionEventが一体どのボタンで発生したものなのかを区別する手がかりとなります。つぎのaddActionListener(リスナー)というメソッドは、ボタン上で発生するイベントのリスナーを指定するものです。これも一つ一つのボタンについて設定します。ここではアプレット自身がリスナーとなるためthisが引数として与えられています。最後の1行は、Appletクラスが持っているメソッドaddを用いて、ボタンonをアプレット本体の上に貼り付ける操作です。addメソッドは引数としてGUIパーツ全般をとります。これにより、ボタンがアプレット上に表示されるようになるのです。

最後に「アプレットの初期状態の設定」をしておきます。これはあらかじめ用意したboolean型変数にfalseを与えることで完了します。

initメソッドの次にあるのは、ActionEventのリスナーメソッド、actionPerformedメソッドの定義です。on/offいずれかのボタンが押される度に、このメソッドが呼び出され処理が実行されます。仮引数は当然ActionEventです。処理内容は次の3つです。

「発生したActionEventのコマンド名を取得」はgetActionCommandメソッドで行います。プログラムの次の部分を見てください。

// イベントのコマンド名を受け取る
String command = e.getActionCommand();

このメソッドはActionEventのもので、コマンド名を文字列で返します。従って代入文を用い、左辺に文字列型の変数を用意し、そこに代入します。

「取得したコマンド名を手がかりにon/offを判断」は、if文の条件文で行っています。一つめの条件文は次のようになっています。

if (command.equals("ON"))

commandは、コマンド名が入っている文字列型の変数です。ここでは文字列、すなわちStringクラスのメソッドequalsが用いられています。このメソッドは引数として与えられた文字列と自分自身(この例ではcommandの中身の文字列)とを比較し、同じならばtrueを、異なる場合にはfalseを返します。つまりこの記述の場合、「commandの中身と文字列ONを比較して同じならば条件成立」という意味になるわけです。今回の例ではelse ifも用意されており、それぞれコマンド名がON(→"On"ボタンが押された場合)とコマンド名がOFF(→"Off"ボタンが押された場合)とを判別しています。さらに、ONの場合には変数SFCにtrueを代入、OFFの場合にはfalseを代入して、アプレットの状態を決定します。

これらの後にrepaintで再描画を行います。

最後にpaintメソッドが定義されています。今回の場合は、処理内容としてif文を用いて次のように記述されています。

// アプレットの状態が「表示」の場合のみ、文字列「SFC」を表示する
if (SFC == true){
		g.drawString("SFC", 50, 50);
}

この場合、変数SFCの中身がtrueである場合のみ、drawStringで文字列SFCの表示を行います。falseならばなにも行いません。変数SFCは、ボタンが押されactionPerformedメソッドが呼び出されて実行された際に設定されています。"On"ボタンが押されたならば変数SFCの中身はtrueであり、再描画が行われるときに文字列SFCの表示が行われます。"Off"ボタンが押された場合は変数SFCはfalseで、再描画が実行されるとなにも表示されない状態になります。

練習問題 8-1

先ほどのプログラムを参考に、今度は2つの画像を用意し、2つのボタンで表示を切り替えるアプレットを作成しなさい。

→ プログラムの実行結果

8.2 newという命令と、クラスの「実体」について

ここでは、さきほど後で詳しく触れるとしておいた、newという命令の意味とその背景にあるJavaの重要な概念について説明しておきます。

ボタンを利用する場合、その準備として最初にnewを使って「実体」を用意しました。この部分の記述を一般化すると、次のようになります。

クラス名 変数名 = new クラス名(); ←但し()内には必要に応じて引数が与えられる場合がある

newという命令は一般に、クラスの「実体」を新しくつくる場合に用いられる命令です。newは単独で機能する命令ではなく、必ず後に上述の「クラス名()」という記述と組み合わせて使われます。この「クラス名()」という記述はコンストラクタと呼ばれます。

「new コンストラクタ」の記述が実行されると、たとえばButtonクラスからプログラムの中で使われる個々のボタン、すなわちButtonクラスの「実体」が作成されます。この「実体」は、左辺に用意された変数の中に記憶されます。

クラスから「実体」を生み出すという発想は、GUIパーツを利用する場合に限らず、Javaプログラミングにおいてしばしば登場するものです。Javaプログラミングの基本となるこの発想については、次のことを知っておいてください。

これはGUIパーツに限らずJavaプログラミング全般に当てはまる原則です。この原則を踏まえて今まで書いてきたプログラムを見直すと、たとえば、「Graphicsクラスのオブジェクト(paintメソッドの仮引数として登場する「Graphics g」の「g」)」や「各種イベントのオブジェクト(MouseEvent、ActionEvent、ItemEventなど、リスナーメソッドの仮引数として登場する「e」)」などの「オブジェクト」が利用されていることが分かります。

Javaにおいては、便利なメソッド群を実装したクラス群がすでに用意されており、それを適宜用途に応じて利用しながらプログラムを作成してゆきます。たとえば文字を表示したり図形を描きたければ、Graphicsクラスという描画関係のメソッドを持ったクラスが存在します。文字を表示するならばdrawString、楕円形を描くならばdrawOvalといったように、目的に応じてGraphicsクラスに実装されているメソッドの中から適切なものを選び、利用すればよいわけです。ただしその際に次の原則があります。

オブジェクト名.メソッド名();

たとえばGraphicsクラスのdrawStringメソッドを用いるのならば、「g.drawString(...)」と記述していましたね。この原則があるために、利用したいクラスのオブジェクトがまだどこにも存在していない場合には、先ほどの「new コンストラクタ」でオブジェクトを作成するという手続きが必要となるのです。

最後に、クラスとオブジェクトの関係を整理しましょう。

というわけで、これらの考え方を踏まえつつ、今まで作成してきたプログラムを見直してみてください。

8.3 チョイス・ボタンを用いたアプレット

次は、複数の選択項目の中から一つの項目を選ぶチョイス・ボタンを使ってみましょう。チョイス・ボタンを用いると、たとえば次のようなアプレットをつくることができます。

上のアプレットには一つのチョイス・ボタンが用いられています。チョイス・ボタンの中には3つの選択項目があり、ユーザーがマウスで項目を選ぶと、それに対応した画像が表示されます。

→ プログラムの実行結果

チョイス・ボタンを用いるためには、大まかにいえば次の3つの準備が必要です。

ここでは2つめと3つめの準備について、より詳しく説明しておきます。

2つ目の準備「Choiceクラスを用いて...」はinitメソッドの中で行います。まず最初に、先ほどのボタン同様、Choice型の変数を用意して、以下のようにチョイス・ボタンのオブジェクトを作成します。

Choice c = new Choice();

ボタンの時はコンストラクタの引数として「表面に表示する文字列」を引与えましたが、ここでは必要ありません。単に()としておきます。

次に、アプレット本体の上に、作成したチョイス・ボタンを加えます。これもボタンの時と同様Appletクラスのadd()で行います。

さらに、チョイス・ボタンの選択項目をつくらなければなりません。これは、選択項目として表示する文字列を引数としてとる、Choiceクラスのメソッドadd(注意! Appletクラスのaddと混同しないように!!)を用いて行います。たとえばChoiceのオブジェクト名がcなら次のようにします。

c.add("項目1");
c.add("項目2");
c.add("項目3");
   .
   .
   .

以上のように、必要な選択項目を必要なだけ加えてゆきます。

最後に、アプレット自身をItemEvent(ユーザーがチョイス・ボタンで項目を選択すると発生するイベント)のリスナーとして設定します。これはChoiceクラスのaddItemListenerメソッドを使って

c.addItemListener(this);

というふうに行います。これで、initで行う準備は完了です。

次に、先ほど3番目にあげた「itemStateChangedメソッドの定義」について説明します。このメソッドはItemEventが発生すると呼び出されます。従って引数は当然ItemEventです。

このメソッドが呼び出されたときに、どの選択項目が選ばれたのかを知る必要があるならば、ItemEventクラスのgetItemメソッドを利用します。itemStateChangedメソッドの定義内で、たとえば次のように記述します。

String s;
s = (String)e.getItem();

「(String)e.getItem()」と記述すると、選択された項目を表す文字列(initの定義内でc.add("項目名")で記述した、その項目名)が返されます。従ってあらかじめ文字列型の変数を用意しておき、代入文の左辺に置いておけばいいのです。

というわけで、最初に示したサンプルプログラムの骨組みは、以下のようになります。

/**
 * 第8週 GUIを用いたアプレット
 * チョイス・ボタンにより表示する画像(えび、ひらめ、こんぶ)を切り替える
 **/
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;

public class ChoicePic extends Applet implements ItemListener{

	int state;		// アプレットの3種類の状態(えび/ひらめ/こんぶ)を記憶する変数
				// えびは0、ひらめは1、こんぶは2が表す
	Image imgs[];		// 3つの画像を記憶する配列

	
	// initメソッド:アプレットの初期化を行う	
	public void init(){
	
		// 3つの画像を読み込む
		......
					
		// チョイス・ボタンを用意する
		Choice c = new Choice();	
		
		// チョイス・ボタンがアプレットのインターフェイスとして機能するための準備をする
		add(c);
		c.add("Ebi");		// チョイス・ボタンの項目にEbiを追加する
		......		// チョイス・ボタンの項目にHirameを追加する
		......		// チョイス・ボタンの項目にKonbuを追加する
		c.addItemListener(this);	// チョイス・ボタンの選択によって発生したイベントのリスナーは
						// アプレット自身であると定める
		
		// アプレットの初期状態を「えびの表示」の状態にしておく
		state = 0;
	
	}
	
	
	// itemStateChangedメソッド:チョイス・ボタンが選択されたときに発生するイベントの処理を行う
	public void itemStateChanged( ItemEvent e ){
	
		// 選択された項目を表す文字列を受け取る
		String item = (String)e.getItem();
		
		// コマンド名を手がかりに押されたボタンを判別
		// 押されたボタンに応じてアプレットの状態を決定する
		if (...){			// 選択された項目がEbiの場合
			......		// アプレットの状態を「0(→えびの表示)」に設定する
		}
		else if(...){ 		// 選択された項目がHirameの場合
			......		// アプレットの状態を「1(→ひらめの表示)」に設定する
		}
		else if(...){ 		// 選択された項目がKonbuの場合
			......		// アプレットの状態を「2(→こんぶの表示)」に設定する
		}
		
		// 再描画を行う
		repaint();
	}
	
	
	// paintメソッド:アプレット本体を表示する
	public void paint(Graphics g){
	
		......	// アプレットの状態に応じて画像の表示を行う
	}
	
}
  

練習問題 8-2

以上の骨組みを元に、3種類の画像をチョイス・ボタンで切り替えるアプレットを完成しなさい。


>> 目次ページへ