7. イベント処理

Java のイベント処理のしかたについて説明します。

(1) ボタンを押しても動かない

 前回、ボタンを使ってレイアウトを3種類見てきました。これらのボタンを押しても何も起こりませんでしたが、これはイベント処理をしていないからです。

 Java ではイベント処理を行う場合、 DelegationEventModel というモデルを使います。このモデルを使っていく場合、2つの言葉が出てきます。1つはイベントソース、もう1つはリスナです。

 たとえば、「ボタンを押すとメッセージを表示する」という処理を書きたい場合、ボタンを押すと「ボタンが押された」というイベントが発生します。そして、このイベント発生を受けて、メッセージを表示する処理が動きだします。

 このとき、イベントを発生させることになったコンポーネント、つまりボタンがイベントソースとなります。そして、メッセージを表示する処理を行うものがリスナになります



(2) イベントが処理されるまで

 イベントソースはこの後に出てくる Button や List のようなコンポーネントのクラスが担当します。イベント処理はリスナが担当します。この2つは基本的には別々の物なので、「このイベントソースでイベントが発生したら、 このリスナで処理をする」という関連付けをしてやらなければなりません。この関連づけのことをリスナの登録といいます。Java ではイベントソースにリスナを登録することで、関連づけを行います。


 先ほどのボタンを押すという例に戻ってイベント処理の流れを追っていきます。 Java ではボタンを押したとき、ActionEvent という名前のイベントが発生します。 ActionEvent はイベント名ですが、これは java.awt.event パッケージに定義されているクラス名でもあります。

 Java ではイベントが発生すると、イベントオブジェクトというものが生成されます。ActionEvent が発生すると、ActionEvent オブジェクトが生成されます。このイベントオブジェクトにはどこでどんなイベントが発生したか、というような情報が入っています。

 イベントが発生すると、ボタンに登録されているリスナに「イベントが発生しましたよ」 という通知が行きます。このとき、同時にイベントオブジェクトもリスナに渡します。通知を受けたリスナは実際にその後のイベント処理(メッセージの表示など)を行います。

 このとき、リスナではイベント処理用のメソッドとしてあらかじめ決められているメソッドを実行します。ActionEvent の場合には actionPerformed( ) というメソッドを実行すると決められています。

イベントソースやイベントは自分で作ることもできます。


(3) リスナの作り方と登録

 イベントを処理するリスナには作り方にいくつかのルールがあります。1つは、イベントを処理するためのメソッドが決まっているということ。もう1つは、イベント処理用のメソッドはインタフェースに定義されているので、これを実装したクラスを作るということです。

 ActionEvent の場合、このイベントを処理するためのメソッドは、 actionPerformed(ActionEvent e) という名前のメソッド、と決められています。そして、このメソッドは自分で勝手に作るのではなく、 ActionListener というインタフェースに定義されている actionPerformed( ) をオーバーライドする、というように決まっています。

 ですから、ActionEvent を処理するリスナのクラスは、

// MyHandler.java
import java.awt.event.*;

class MyHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        System.out.println("ボタンがおされたよ");
    }
}

 というように書いていきます。 ActionEvent クラス、ActionListener インタフェースが java.awt.event パッケージにあるのでインポートして使います。

 これでリスナはできあがったので、次にボタンとこのリスナの関連づけ、リスナの登録を行います。 ActionEvent を処理するリスナを登録するメソッドは、 addActionListener(ActionListener l) という形式のメソッドです。この登録用のメソッドは各コンポーネントのクラスが持っています。ボタンの場合は Button クラスに定義されています。

 addActionListner の引数の型は ActionListener 型になっていますが、 これは Actionlistener インタフェースを実装したクラスのオブジェクトが指定できるという意味です。

 次の例では1つのソースファイル内に2つのクラスを定義していますが、別のソースファイルに定義しても構いません。

  ActionTest.java

// ActionTest.java

import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;

public class ActionTest extends Applet {
    public void init() {
        // ボタン作成・追加
        Button b = new Button("OK");
        add(b);

        // リスナ登録 (ボタンにリスナを登録する)
        MyHandler handle = new MyHandler();
        b.addActionListener(handle);
    }
}

// リスナ
class MyHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        System.out.println("ボタンがおされたよ");
    }
}


  ActionTest.html

<APPLET CODE=ActionTest.class width=200 height=100>
</APPLET>


  実行例  (画像をクリックすると実際のActionTest.html のアプレットが起動します)



 ボタンを押すと MS-DOS プロンプトに「ボタンが押されたよ」というメッセージが出てきます。ブラウザで実行した場合には Java コンソールに表示されます。

  ActionTest.html

C:\java_test>appletviewer ActionTest.html
ボタンがおされたよ

Java コンソールはブラウザの設定で、「Java コンソールを有効にする」というオプションを選択します。


(4) その他のイベントの種類

 ここまでは ActionEvent について見てきましたが、他にもたくさんのイベントがあります。たとえば、マウスをクリックしたときには MouseEvent が発生します。他にも ItemEvent や WindowEvent などがあります。イベントが変わってもリスナの作り方、登録の仕方同じです。

 違うところといえば、イベント処理用のメソッド名(メソッドを定義してあるインタフェース名)が違うこと、そして登録用メソッド名が違うということです。

 MouseEvent なら、MouseListener、addMouseListener( )、 ItemEventなら、ItemListener、addItemListener( ) というようにある程度はメソッド名に決まりがあります。詳しくは、このあとの章、または API ドキュメントを見てください。

 ここでは、MouseEvent の例を挙げておきます。先ほどはリスナのクラスを別にしましたが、1つのクラス内にまとめることもできます。

  MouseEventTest.java

import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;

public class MouseEventTest extends Applet implements MouseListener {
    public void init() {
        // リスナ登録
        // このクラス(Applet)がイベントソースでリスナになる
        addMouseListener(this);
    }
    
    // MouseListenerに定義されている5つのメソッド
    public void mouseClicked(MouseEvent e) {
        System.out.println("クリックされました");
    }
    
    // メソッドがイベント処理に必要が無いときも、
    // インタフェース内のメソッドは
    // すべてオーバーライドする必要があります

    // マウスボタンが押された
    public void mousePressed(MouseEvent e) {
    }
    // マウスボタンが放された
    public void mouseReleased(MouseEvent e) {
    }
    // イベントソース(アプレット)にマウスポインタが入った
    public void mouseEntered(MouseEvent e) {
    }
    // イベントソース(アプレット)からマウスポインタが出た
    public void mouseExited(MouseEvent e) {
    }
}


  MouseEvent.html

<APPLET CODE=MouseEventTest.class width=250 height=200>
</APPLET>


  実行例  (画像をクリックすると実際の ActionTest.html のアプレットが起動します)


 この例題では、アプレットをクリックすると MS-DOS プロンプト(又は Java コンソール)にメッセージが表示されます。今回はクリックするイベント mouseClicked( ) しか使っていませんが、必要がなくてもインタフェース内のメソッドはオーバーライドします (入門編17章参照)。

 ほかの4つのメソッドにもメッセージを表示する処理を追加して、イベントが発生するタイミングを確認してみましょう。


(5) イベントオブジェクトの使いみち

 イベント処理用のメソッドは、イベントオブジェクトが受け取れます。たとえば、actionPerformed(ActionEvent e) なら、ActionEvent オブジェクトを e という変数で使うことができます。

 イベントオブジェクトは EventObject というクラスのサブクラスです。このクラスにはイベントの詳細情報を得るためのメソッドがあります。


 たとえば、ボタンが2つあったとき、この2つのボタンに同じリスナを登録すると、どちらのボタンを押しても同じ actionPerformed が実行されます。このとき、この2つのボタンを判別したい場合はどうしたらよいでしょう。

 ここで先に挙げた、getSource( ) や getActionCommand( ) を使います。getSource( ) では押したボタンのオブジェクトが戻り値としてそのまま返ってきます。ただし、型は Object です。また、getActionCommand( ) は、ボタンの場合はラベルが返ってきます。

 これらの情報を利用して、イベントソースを判断したり、詳細情報を得たりします。

import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;

public class EObjectTest extends Applet implements ActionListener {
    Button b1,b2;
    
    public void init() {
        // ボタン作成・追加
        b1 = new Button("One");
        b2 = new Button("Two");
        add(b1);
        add(b2);

        // リスナ登録
        b1.addActionListener(this);
        b2.addActionListener(this);
    }

    public void actionPerformed(ActionEvent e) {
        // getSource() でイベントソースのオブジェクトを獲得し
        // Button クラスにキャストする
        Button b = (Button)e.getSource();

        // getActionCommand() でボタンのラベルを獲得する
        System.out.println("Label : "+e.getActionCommand());
        // getSource() で獲得したオブジェクトとはじめに作った
        // ボタンのオブジェクトが一致するか調べる

        if (b==b1) {
            System.out.println("Oneのボタン");
        }
        if (b==b2) {
            System.out.println("Twoのボタン");
        }
        
        // ボタンのラベルで比較する場合には
        // String クラスの文字列比較用のメソッド equals() を使って
        // if ( e.getActionCommand().equals("One") ) とします
    }
}

<APPLET CODE=EObjectTest.class width=250 height=100>
</APPLET>


 実行例  (画像をクリックすると実際の EObjectTest のアプレットが起動します)



 One のボタン Two のボタンがそれぞれ区別されているのがわかります。

C:\java_test>appletviewer EObjectTest.html
Label : One
Oneのボタン
Label : Two
Twoのボタン

EventObject のサブクラス(ActionEventやMouseEvent)では、他にも詳細情報を調べるためのメソッドが用意されています。たとえば、MouseEvent クラスの getX( )、getY( ) ではクリックされた座標がわかります。

前の章(6.レイアウトマネージャ)   次の章(8.Label/Button)