学生向けプログラミング入門

学生向けにプログラミングを解説。Java、C++、Ruby、PHP、データベース

Javaプログラミング入門その28 イベント処理を行うプログラム

<<前  [TOP]  次>>


Javaのイベント処理は、「イベント駆動型」と呼ばれる処理で行います。
イベント駆動型とは、オブジェクトに何らかのイベントが発生した場合はあらかじめ定義された事柄を実行する方法で、イベントが発生したかどうかはアプリケーションで判断して、それに対応する処理を行います。
こうすることにより、プログラマーは「イベントを待ち受ける」というようなプログラムを記述する必要が無くなり、「何が起こったときに何をする」という処理を記述することに専念できます。
Javaでのイベント処理は、イベント駆動型の処理を複数のオブジェクトを組み合わせて行っています。
「発生源のオブジェクト」->「イベントのオブジェクト」->「リスナのオブジェクト」


例えば、キャンバス上でマウスクリックされたとします。
この場合、「発生源はCanvas」->「イベントはMouseEvent」->「MouseEventを受け取って処理するリスナはMouseListener」というようになります。


まずはイベント処理(クローズボタンで終了)を行うフレームを作成するプログラムを作ってみましょう。
以下のサンプルプログラムを作成して下さい。


MyFrame.java 直

import java.awt.*;
import java.awt.event.*;

public class MyFrame extends Frame implements WindowListener {

	/**コンストラクタ*/
	public MyFrame(String frameName) {

		//フレームのタイトルを設定
		setTitle(frameName);

		//スレームで発生したイベント通知用として登録
		addWindowListener(this);
	}

	/**ウィンドウをクローズした時の処理*/
	public void windowClosing(WindowEvent evt) {

		dispose();	//ウィンドウを閉じる
	}

	/*ウィンドウクローズ後の処理*/
	public void windowClosed(WindowEvent evt) {

		System.exit(0);	//プログラム終了
	}

	/**その他のウィンドウ処理*/
	public void windowDeiconified(WindowEvent evt) { }
	public void windowIconified(WindowEvent evt) { }
	public void windowOpened(WindowEvent evt) { }
	public void windowActivated(WindowEvent evt) { }
	public void windowDeactivated(WindowEvent evt) { }

	/**main()メソッド*/
	public static void main(String[] args) {

		MyFrame frame = new MyFrame("MyFrameTest");
		frame.setSize(200,100);
		frame.setVisible(true);
	}
}



リスナでは通知されたイベント情報から、「○○のアクションがあった場合」というようにアクションに対応したメソッドが設定されていますので、プログラムでは、これらのメソッドの実装を行う必要があります。
リスナはインターフェイスですので、implementsする必要があります。
また、リスナはオブジェクトに登録することで利用可能になりますから、implementsしていても、登録しなければオブジェクトへのイベントがリスナに通知されることはありません。
登録には「add○○Listener()」を用います。

import java.awt.event.*;    //AWTのイベントはjava.awt.eventパッケージで定義

public class Test implements MouseListener {

    /**マウスがクリックされたときの処理*/
    public void mouseClicked(MouseEvent evt) {
        //処理
     }

    /**その他のマウス処理(リスナを利用する場合、処理はなくても空で実装する)*/
    public void mouseEntered(MouseEvent evt) { }
    public void mouseExited(MouseEvent evt) { }
    public void mousePressed(MouseEvent evt) { }
    public void mouseReleased(MouseEvent evt) { }

    public static void main(String[] args) {
        Canvas c = new Canvas();
        c.addMouseListener(this);    //イベント通知用のリスナをCanvasに登録
     }
}



イベントに対応する処理を行う方法としては、このほかにAdapterクラスと呼ばれるものを利用する方法があります(MouseListenerインターフェイスに対応するのはMouseAdapterクラス)。
Adapterは、リスナを利用する際必ず実装しなければいけなかったメソッドをあらかじめ「空で定義」してあるクラスというだけです。
ですからAdapterクラスを継承(extends)したクラスでは「空定義メソッド」は記述する必要はありません。


AWTでのイベントのクラス構成は以下のようになっています(今回使用するイベントは、WindowEvent・KeyEvent・MouseEvent)。

java.lang.Object
    +--java.util.EventObject
        +--java.awt.AWTEvent
            |
            +--java.awt.event.ActionEvent
            +--java.awt.event.AdjustmentEvent
            +--java.awt.event.ItemEvent
            +--java.awt.event.TextEvent
            +--java.awt.event.HierarchyEvent
            +--java.awt.event.InputMethodEvent
            +--java.awt.event.InvocationEvent
            +--java.awt.event.ComponentEvent
                |
                +--java.awt.event.ContainerEvent
                +--java.awt.event.FocusEvent
                +--java.awt.event.PaintEvent
                +--java.awt.event.WindowEvent
                +--java.awt.event.InputEvent
                    |
                    +--java.awt.event.KeyEvent
                    +--java.awt.event.MouseEvent
                        |
                        +--java.awt.event.MouseWheelEvent



上記イベントの発生が通知されるリスナ(あるいはAdapter)と実装すべきメソッドは以下のようになっています。
なお、親インターフェイスはjava.util.EventListenerです。

インターフェイス名対応するAdapter受け取るイベントとその働き実装すべきメソッド
ActionListenerなしActionEvent
ボタンのクリックなど
actionPerformed()
AdjustmentListenerなしAdjustmentEvent
位置などの調整
adjustmentValueChanged()
ItemListenerなしItemEvent
チェックボックスの項目選択など
itemStateChanged()
TextListenerなし TextEvent
テキストの値が変更
textValueChanged()
InputMethodListenerなしInputMethodEvent
インプットメソッドを利用して変換されるテキスト
inputMethodTextChanged()
caretPositionChanged()
HierarchyListenerなしHierarchyEvent
断層変更
hierarchyChanged()
HierarchyBoundsListenerHierarchyBoundsAdapterHierarchyEvent
移動およびサイズ変更された上位クラスのイベント
ancestorMoved()
ancestorResized()
ComponentListenerComponentAdapterComponentEvent
コンポーネントの移動やサイズ変更など
componentResized()
componentMoved()
componentShown()
componentHidden()
ContainerListenerContainerAdapterContainerEvent
コンテナの追加や削除など
componentAdded()
componentRemoved()
FoucusListenerFoucusAdapterFocusEvent
コンポーネントの入力フォーカスの取得など
focusGained()
focusLost()
WindowListenerWindowAdapterWindowEvent
ウィンドウの状態変化
windowOpened()
windowClosing()
windowClosed()
windowIconified()
windowDeiconified()
windowActivated()
windowDeactivated()
WindowFoucusListenerなしWindowEvent
ウィンドウの状態変化
windowGainedFocus()
windowLostFocus()
WindowStateListenerなしWindowEvent
ウィンドウの状態変化
windowStateChanged()
KeyListenerKeyAdapterKeyEvent
キー入力が発生
keyTyped()
keyPressed()
keyReleased()
MouseListenerMouseAdapterMouseEvent
マウスのアクション
mouseClicked()
mousePressed()
mouseReleased()
mouseEntered()
mouseExited()
MouseMotionListenerMouseMotionAdapterMouseEvent
マウスのアクション
mouseDragged()
mouseMoved()
MouseWheelListenerなしMouseEvent
マウスのアクション
mouseWheelMoved()


リスナを登録するには先に述べたようにオブジェクト(今回はコンポーネント)に対して、「add○○Listener(リスナ)」を用います。
今回使用するのは、WindowListener、MouseListener、KeyListenerですから、以下のようになります(各リスナはimplementsされているとします)。

Frame f = new Frame();
Canvas c = new Canvas();
f.addWindowListener(this);    //WindowListenerを登録
c.addMouseListener(this);    //MouseListenerを登録
c.addKeyListener(this);      //KeyListenerを登録

引数には実行処理を定義したリスナを指定します(addWindowListenerならWindowListenerオブジェクト)。
今回は自分のクラスにimplementsされているのでthisとしています。


WindowListenerは発生したWindowEventをもとに以下のメソッドを実行します。

メソッド(引数はWindowEvent)起こったマウスのアクション
windowOpened()最初に可視になったとき
windowClosing()閉じようとしたとき
windowClosed()閉じられたとき
windowIconified()アイコンになったとき
windowDeiconified()アイコンから復帰したとき
windowActivated()アクティブウィンドウになったとき
windowDeactivated()アクティブウィンドウでなくなったとき


リスナはインターフェイスですので、必ず実装しなければいけないメソッドがあります。
メソッドの実装忘れや、メソッド名を間違えるとコンパイルエラーが出ます。

public class MyFrame extends Frame implements WindowListener {

Frameクラスを継承し、WindowListenerを実装しています。


サンプルプログラム「MyFrame.java」を実行してみましょう。
「クローズボタンで終了」できるフレームができます。
大きさは「200,100」で背景は白です。








キャンバスでキーボードとマウスの入力を受け付けるサンプルプログラムを作成してみましょう。
このプログラムは、上で作成した「MyFrame.java」を利用しています。


EventTest1.java 直

import java.awt.*;
import java.awt.event.*;

public class EventTest1 extends Canvas implements KeyListener, MouseListener, Runnable {

	private final int MAX_IMAGE = 7;
	private final int WIDTH = 500;
	private final int HEIGHT = 400;
	private Image[] image = new Image[MAX_IMAGE];
	private MediaTracker tracker;

	//ダブルバッファリング(オフスクリーン・バッファ用)変数
	private Graphics offg;
	private Image offImage;
	private int x =0; //画像の座標
	private int y = 100;
	private int w; //画像の幅と高さ
	private int h;
	private int imageNum = 0; //利用する画像
	private int imageCount = 1; //画像の枚数のカウント制御
	private int moveCount = 5; //移動距離カウント制御
	private int mx, my; //マウスの座標取得用

	/**コンストラクタ*/
	public EventTest1() {

		setSize(WIDTH, HEIGHT);
		setBackground(Color.black);

		Toolkit tk = Toolkit.getDefaultToolkit();

		tracker = new MediaTracker(this);

		//キャラクターイメージの作成
		for (int i=0; i<MAX_IMAGE; i++) {

			image[i] = tk.getImage("char" + i + ".gif");
			tracker.addImage(image[i], i);
		}

		//全イメージのダウンロードが終わるまで待つ
		try {

			tracker.waitForAll();
		}

		catch (InterruptedException e) {

			System.err.println("tracker error");
		}

		//キャラクターイメージの幅と高さと取得
		w = image[0].getWidth(this);
		h = image[0].getHeight(this);

		//Canvasで発生したイベントを通知
		addKeyListener(this);
		addMouseListener(this);

	}

	/**メインの処理(スレッド処理)*/
	public void run() {

		while (true) { //永久に繰り返し

			try {
				Thread.sleep(100); //100ミリ秒(0.1秒)スリープ
			}

			catch (InterruptedException ex) {
				System.err.println(ex);
			}

			repaint();
		}
	}

	/**再描写が必要な場合の処理*/
	public void update(Graphics g) {

		//キャラクタ、障害物の消去(全画面消去)
		//オフスクリーン・バッファへの描き込み。実際にはまだ見えない
		offg.setColor(Color.black);
		offg.fillRect(0, 0, WIDTH, HEIGHT);

		//口を開けるアニメか、閉じるアニメかを設定
		if(imageNum >= (MAX_IMAGE-1)) {

			imageCount = -1;
		}
		else if (imageNum <= 0) {

			imageCount = 1;
		}
		imageNum+=imageCount;

		//オフスクリーン・バッファへの描き込み。実際にはまだ見えない
		offg.drawImage(image[imageNum], x, y, this);

		//イメージとマウスがクリックされたときの座標を描画
		offg.setColor(Color.yellow);
		offg.drawString("x=" + x + ", y=" + y, 10, 10);
		offg.drawString("mx=" + mx + ", my=" + my, 10, 30);

		//オフスクリーン・バッファへに描かれたものを画面に表示
		g.drawImage(offImage, 0, 0, this);
	}

	/**キャンバスで描写の必要があるときに呼ばれるメソッド*/
	public void paint(Graphics g) {

		//オフスクリーンバッファの領域がない場合は作成
		if (offg == null) {
			//キャンバスと同じ大きさの仮想画面を生成
			offImage = createImage(getSize().width, getSize().height);

			//offImageから仮想画面描画用のグラフィックスコンテキストを取得
			offg = offImage.getGraphics();
		}

		//イメージと文字列の描画
		g.drawImage(image[imageNum], x, y, this);

		g.setColor(Color.yellow);
		g.drawString("x=" + x + ", y=" + y, 10, 10);
		g.drawString("mx=" + mx + ", my=" + my, 10, 30);

	}

	/**キーが押されたときの処理*/
	public void keyPressed(KeyEvent evt) {

		int key = evt.getKeyCode();

		//移動範囲内だけで移動
		if (key == evt.VK_LEFT && x > 0) {

			x -= moveCount;
		}

		else if (key == evt.VK_RIGHT && x < WIDTH-w) {

			x += moveCount;
		}
	}

	/**その他のキー処理*/
	public void keyReleased(KeyEvent evt) { }

	public void keyTyped(KeyEvent evt) { }

	/**マウスがクリックされたときの処理*/
	public void mouseClicked(MouseEvent evt) {

		mx = evt.getX();
		my = evt.getY();
	}

	/**その他のマウス処理*/
	public void mouseEntered(MouseEvent evt) { }

	public void mouseExited(MouseEvent evt) { }

	public void mousePressed(MouseEvent evt) { }

	public void mouseReleased(MouseEvent evt) { }

	/**main()メソッド*/
	public static void main(String[] args) {

		EventTest1 canvas = new EventTest1();

		//自作のクラスMyFrameを利用
		MyFrame frame = new MyFrame("EventTest1");

		frame.add(canvas);
		frame.pack();
		frame.setVisible(true);

		//スレッドを生成して開始(runメソッドの呼び出し)
		new Thread(canvas).start();
	}
}

このプログラムを実行するには画像ファイルが必要です。
char0.gif〜char6.gifをプログラムを保存するのと同じフォルダ(ディレクトリ)に保存してください。
char0.gif 直
char1.gif 直
char2.gif 直
char3.gif 直
char4.gif 直
char5.gif 直
char6.gif 直


MouseListenerは発生したMouseEventをもとに以下のメソッドを実行します。

メソッド(引数はMouseEvent)起こったマウスのアクション
mouseClicked()クリックしたとき
mousePressed()押したとき
mouseReleased()離したとき
mouseEntered()コンポーネントにマウスが入ったとき
mouseExited()コンポーネントからマウスが出たとき
取得した情報は「MouseEventのオブジェクト.get○○」で取り出せます。
例えば「getX()」「getY()」はクリックされたときのマウスカーソルの座標を取得できます。


KeyListenerは発生したKeyEventをもとに以下のメソッドを実行します。
メソッド(引数はKeyEvent)起こったキー入力のアクション
keyTyped()タイプしたとき
keyPressed()押したとき
keyReleased()離したとき
取得した情報は「KeyEventのオブジェクト.get○○」で取り出せます。
例えば、低レベルなイベントのkeyPressed()とkeyReleased()では、「getKeyCode()」で入力されたキーの情報を取り出せます。
このときのキー情報は「VK_UP(カーソル移動キーの上矢印キー)」などの仮想キーコードです。
キーコードの詳細は、APIドキュメントのKeyEventクラスを参照して下さい。

public class EventTest1 extends Canvas implements KeyListener, MouseListener, Runnable {

Canvasクラスを継承し、KeyListenerとMouseListener、Runnableの3つのインターフェイスを実装しています。


ではサンプルプログラムを実行してみましょう。
「クローズボタンで終了」できるフレームができます。
大きさは「500,400」で背景は黒です。
char0.gif〜char6.gifの画像がアニメーションで動きます。
キーボードの←→キーでその画像が移動します。
移動した位置が画面左上に表示されます(x,y)。
フレーム内をマウスでクリックすると、クリックした位置が画面左上に表示されます(mx,my)。








<<前  [TOP]  次>>