Javaプログラミング基礎 講義資料

今回は、グラフィックスの続きとして マウスやキーボードで操作ができるようなプログラムについて学びます。

マウスやキーボードからの入力を受け付ける

ウィンドウ上で、マウスのクリックやキー入力などを行うと、 プログラムに対して「イベント(event)」という信号 (のようなもの) が発せられます。 プログラムではイベントを受け取り、 そのイベントに関するデータ (例えば、マウスの座標やキーの種類など) を 適切に処理します。

イベントが発生したときに実行される部分を イベントハンドラ (event handler) と呼びます。 Javaでは、イベントが発生したときに行うべき仕事を あらかじめメソッドとして書いておき、 イベントの発生に備えて登録しておきます。 このイベントハンドラをまとめたクラスを、 リスナ (listener) と呼びます。

例題: マウスのボタン操作を検出する

マウスのボタンの操作を検出するプログラムを示します。 (MouseChecker.java)

実際に実行して、マウスの反応を見てみましょう。

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

class MouseChecker {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Mouse Checker");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements MouseListener {
    public MyPanel() {
	setBackground(Color.white);
	addMouseListener(this);
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);
    }

    public void mouseClicked(MouseEvent e) {
	System.out.println("マウスがクリックされました");
    }
    public void mouseEntered(MouseEvent e) {
	System.out.println("マウスがパネル内に入りました");
    }
    public void mouseExited(MouseEvent e) {
	System.out.println("マウスがパネル内から出ました");
    }
    public void mousePressed(MouseEvent e) {
	System.out.println("マウスのボタンが押されました");
    }
    public void mouseReleased(MouseEvent e) {
	System.out.println("マウスのボタンが離されました");
    }
}

下線で示した部分が、 マウスのボタン操作を検出し、処理するために必要な記述です。

import java.awt.event.*;

上の記述は、クラスライブラリのイベントに関するクラスを、 デフォルトで使えるようにするための記述です。

class MyPanel extends JPanel implements MouseListener

マウスのボタン操作に関するイベントを受け取るには、 インタフェース MouseListener を実装し、 マウスのボタンの押す操作、離す操作に対応したメソッドを作成する必要があります。

        addMouseListener(this);

上の記述では、このクラス (MyPanel) で、 マウスのボタン操作に関するイベントを受け取るように登録しています。

    public void mouseClicked(MouseEvent e)
    public void mouseEntered(MouseEvent e)
    public void mouseExited(MouseEvent e)
    public void mousePressed(MouseEvent e)
    public void mouseReleased(MouseEvent e)

上の5つのメソッドは、それぞれ、 マウスがクリックされたとき、マウスカーソルがウィンドウ内に入ったとき、 マウスカーソルがウィンドウ外に出たとき、 マウスのボタンが押されたとき、 マウスのボタンが離されたときの、 各タイミングで自動的に実行されるメソッドです。 これらのメソッドにイベントの種類によって適切な処理を書くことになります。

例題: マウスの動きを検出する

マウスのボタン操作に加えて、 マウスの動きを検出するプログラムを示します。 (MouseMotionChecker.java)

実際に実行して、マウスの反応を見てみましょう。

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

class MouseMotionChecker {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Mouse Motion Checker");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements MouseListener,MouseMotionListener {
    public MyPanel() {
	setBackground(Color.white);

	addMouseListener(this);
	addMouseMotionListener(this);
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);
    }

    public void mouseClicked(MouseEvent e) {
	System.out.println("マウスがクリックされました");
    }
    public void mouseEntered(MouseEvent e) {
	System.out.println("マウスがパネル内に入りました");
    }
    public void mouseExited(MouseEvent e) {
	System.out.println("マウスがパネル内から出ました");
    }
    public void mousePressed(MouseEvent e) {
	System.out.println("マウスのボタンが押されました");
    }
    public void mouseReleased(MouseEvent e) {
	System.out.println("マウスのボタンが離されました");
    }

    public void mouseDragged(MouseEvent e) {
	System.out.println("ドラッグ中のマウスの位置: " + e.getX() + "," + e.getY());
    }
    public void mouseMoved(MouseEvent e) {
	System.out.println("マウスの位置: " + e.getX() + "," + e.getY());
    }
}

下線で示した部分が、マウスの動きを検出するための記述です。

マウスの動きを検出するには、 インタフェース MouseMotionListener を実装し、 マウスが動いたときのイベントを処理するメソッドを用意します。 次に、addMouseMotionListener(this) で、 マウスが動いたときのイベントを受け取るように登録します。

ウィンドウ内でマウスの位置が変わると逐次イベントが発生し、 mouseDragged あるいは mouseMoved メソッドが自動的に実行されます。 これらのメソッドに、マウスが動いたときに行う仕事の内容を書くことになります。 また、そのときのマウスカーソルの位置 (座標) を取り出すことができます。 メソッド e.getX() でマウスカーソルのX座標、 メソッド e.getY() でY座標を得ることができます。

座標以外に取り出すことができる情報 (どのボタンが押されていたか、キーが同時に押されたいたか等) など詳しくは、 Java SDK JDK 5.0 ドキュメント の インタフェース MouseEvent の説明を参照してください。

例題: キーボード入力(1)

イベント処理に関する最後の話題として、 キーボードからの入力を受け取る方法を示します。 (KeyChecker.java)

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

class KeyChecker {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Key Checker");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements KeyListener {
    public MyPanel() {
	setBackground(Color.white);

	setFocusable(true);
	addKeyListener(this);
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);
    }

    public void keyPressed(KeyEvent e) {
	System.out.println("キー " + e.getKeyChar() + "が押されました");
    }
    public void keyReleased(KeyEvent e) {
	System.out.println("キー " + e.getKeyChar() + "が離されました");
    }
    public void keyTyped(KeyEvent e) {
	System.out.println("キー " + e.getKeyChar() + "がタイプされました");
    }
}

プログラム全体の構造は、マウスに関するイベント処理のプログラムと同様です。 キー入力を検出するには、 インタフェース KeyListener を実装し、 キーボード入力に関するイベントを処理するメソッドを用意します。 次に、setFocusable(true) でキー入力を受け取る準備をし、 addKeyListener(this) で、 キー入力をしたときのイベントを受け取るように登録します。

キーを押したとき、キーを離したとき、キーをタイプしたとき、それぞれ メソッド keyPressed, keyReleased, keyTyped が自動的に実行されます。

メソッド e.getKeyChar() でキーの内容を取り出すことができます。 e.getKeyChar() の値は「1文字」を表す char 型です。 文字列を表す String オブジェクトに変換するには、

    e.geKeyChar().toString()

のように書きます。

矢印キーや、Alt, Control, Back Space などの制御キーを扱う方法など 詳しくは、 Java SDK JDK 5.0 ドキュメント の クラス KeyEvent の説明を参照してください。

例題: キーボード入力(2)

矢印キーの操作を検出するプログラムを示します。 (ArrowKeyChecker.java)

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

class ArrowKeyChecker {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Arrow Key Checker");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements KeyListener {
    public MyPanel() {
	setBackground(Color.white);

	setFocusable(true);
	addKeyListener(this);
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);
    }

    public void keyPressed(KeyEvent e) {
	if (e.getKeyCode() == KeyEvent.VK_DOWN)
	    System.out.println("↓");
	else if (e.getKeyCode() == KeyEvent.VK_UP)
	    System.out.println("↑");
	else if (e.getKeyCode() == KeyEvent.VK_LEFT)
	    System.out.println("←");
	else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
	    System.out.println("→");
	else {
	    System.out.println(e.getKeyChar());
	}
    }
    public void keyReleased(KeyEvent e) {
    }
    public void keyTyped(KeyEvent e) {
    }
}

例題: マウスカーソルの位置に文字を表示するプログラム

イベントを扱う簡単な例として、 マウスカーソル上にキーボードから入力した文字を表示するプログラムを示します。 (PutLetter.java)

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

class PutLetter {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Put Letter");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements MouseMotionListener, KeyListener {
    int mouseX, mouseY;
    String letter;

    public MyPanel() {
	setBackground(Color.white);

	setFocusable(true);
	addKeyListener(this);
	addMouseMotionListener(this);

	letter = "";
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);

	System.out.println("ウィンドウの内容が変更されたので再描画します");
	g.setColor(Color.black);
	g.drawString(letter, mouseX, mouseY);
    }

    public void mouseDragged(MouseEvent e) {
    }
    public void mouseMoved(MouseEvent e) {
	System.out.println("マウスの位置: " + e.getX() + "," + e.getY());
	mouseX = e.getX();
	mouseY = e.getY();
    }

    public void keyPressed(KeyEvent e) {
	System.out.println("キー " + e.getKeyChar() + "が押されました");
	char ch = e.getKeyChar();
	letter = Character.toString(ch);

	repaint();
    }
    public void keyReleased(KeyEvent e) {
    }
    public void keyTyped(KeyEvent e) {
    }
}

このプログラムでは、マウスの動きとキー入力に関するイベント処理を行うので、 インタフェース MouseMotionListener と KeyListener を実装します。

    int mouseX, mouseY;
    String letter;

クラス MyPanel では、 マウスカーソルの座標情報を入れるための int mouseX, mouseY と、 入力された文字を入れるための String letter の3つの属性を用意します。

マウスが移動した際に実行されるメソッド MouseMoved では、 マウスが移動するたびに、mouseX, mouseYの値を更新するようにします。

キーを押した際に実行されるメソッド KeyPressed では、 押した文字を letter に代入するようにします。 ここでメソッド repaint() の実行に注目してください。 メソッド repaint は、 ウィンドウ内の内容を更新したいときに、再度描画を行わせるメソッドです。 具体的には、repaint() を実行すると、 ウィンドウ内が一旦クリアされ、 メソッド paintComponent(Graphics g) が自動的に実行されるようになっています。 結果として、画面が書き換わり、 マウスカーソルの位置に入力した文字が表示されることになります。

メソッド paintComponent(Graphics g) は、 repaint() によって実行されるだけではありません。 複数のウィンドウが重なり、 このプログラムのウィンドウが後ろになってしまうと、 ウィンドウの中身が別のウィンドウにかくれて見えなくなります。 この状況でこのプログラムのウィンドウを最前面に移動させると、 ウィンドウの中身を新たに書き直さなければなりません。 このようなケースでも paintComponet(Graphics g) は実行されるのです。

アニメーションとイベント処理を組み合わせたプログラム

例題: ボールのアニメーション(2)

先週のボールのアニメーションに、マウスの動きを検出する処理を加え、 ボールをドラッグして移動できる機能を加えた例を示します。 (BallAnimation2.java)

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

class BallAnimation2 {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Ball Animation");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements Runnable, MouseMotionListener {
    private Ball ball;

    public MyPanel() {
	setBackground(Color.white);
        // マウスを動かしたときのイベント処理を行うように登録
	addMouseMotionListener(this);

	ball = new Ball(100,100,1,1,0,0,610,430);

	Thread refresh = new Thread(this);
	refresh.start();
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);

	ball.forward();
	g.setColor(Color.red);
	g.fillOval(ball.getX(), ball.getY(), 20, 20);
    }

    // マウスをドラッグしたとき、その座標にボールを移動させる
    public void mouseDragged(MouseEvent e) {
	ball.setX(e.getX());
	ball.setY(e.getY());
    }
    public void mouseMoved(MouseEvent e) {
    }

    public void run() {
	while(true) {
	    repaint();
	    try {
		Thread.sleep(10);
	    }
	    catch(Exception e) {
	    }
	}
    }
}

class Ball {
    private int x;
    private int y;
    private int vx;
    private int vy;
    private int left;
    private int right;
    private int top;
    private int bottom;

    public Ball(int x, int y, int vx, int vy, int l, int t, int r, int b) {
	this.x = x;
	this.y = y;
	this.vx = vx;
	this.vy = vy;
	right = r;
	left = l;
	top = t;
	bottom = b;
    }

    public void forward() {
	if (x + vx < left || x + vx > right) 
	    vx = -vx;
	if (y + vy < top || y + vy > bottom) 
	    vy = -vy;
	x = x + vx;
	y = y + vy;
    }

    public int getX() {
	return x;
    }

    public void setX(int x) {
	this.x = x;
    }

    public int getY() {
	return y;
    }

    public void setY(int y) {
	this.y = y;
    }
}