2-6:イベント処理組み込みの実例


・ イベント処理の実際の方法を、マウスイベントの処理を例にとって解説しましょう。 マウスの出入りに応じて描画内容が変化するアプリケーションを考えてみます。 代理人モデルの考え方をはっきりわかるようにするため、 絵を描くためのキャンバス(Canvasのサブクラス)と、 マウスのイベントを処理するアダプタのクラス (MouseAdapterのサブクラス)を別々に設計することにします。
まず、キャンバスの主要部分は次のようになるでしょう。


/** マウスの操作で表示が反転する RevName のクラス定義 */
import java.awt.*;
import java.awt.event.*;
public class RevName extends Canvas {
 
   /** アダプターのオブジェクト */
        public ReverseAdapter adapter;

   /** 表示する文字列 */
        public String message = "Wakkanai Hokusei";
 
   /** マウスがキャンバス内にあるかどうかを示すフラグ */
        protected boolean stateFlag = false;
 
   /** コンストラクタ */
        public RevName() {
               super();
               setSize( 200, 40 );
               adapter = new ReverseAdapter();
               addMouseListener( adapter );  // アダプタの登録
        }
 
   /** グラフィックを描くメソッド */
        public void paint( Graphics g ) {
               if( stateFlag == false ) {   // マウスポインタが外にある
                   g.setColor( Color.yellow );
                   g.fill3DRect( 1, 1, 198, 38, true );
                   g.setColor( Color.black );
                   g.drawString( message, 5, 22 );
               } 
               else {   // マウスポインタが中にある
                   g.setColor( Color.black );
                   g.fill3DRect( 1, 1, 198, 38, false );
                   g.setColor( Color.yellow );
                   g.drawString( message, 5, 22 );
                }
        }
                         :
                         :

上のプログラムでは、この後定義するアダプタのオブジェクトを1個生成しています。 addMouseListener()メソッドで、 アダプタのオブジェクトを登録している点に注目してください。

・ 一方、アダプタのクラスは次のようになります。 MouseAdapter はマウスポインタの出入りとマウスボタンのクリックに関連する 5個のメソッドを実装しますが、ここではマウスポインタの出入りに関連する mouseEntered() と mouseExited()の内容を定義します。


/** マウスの操作を処理する ReverseAdapter のクラス定義 */
import java.awt.*;
import java.awt.event.*;
public class ReverseAdapter extends MouseAdapter {

   /** マウスがアプレット内に入った時に自動的に呼び出される */
        public void mouseEntered( MouseEvent evt ) {
               RevName rev = (RevName)(evt.getSource());
               rev.stateFlag = true;
               rev.repaint();    // キャンバスの paint() を呼び出す
        }
 
   /** マウスがアプレットの外に出た時に自動的に呼び出される */
        public void mouseExited( MouseEvent evt ) {
               RevName rev = (RevName)(evt.getSource());
               rev.stateFlag = false;
               rev.repaint();    // キャンバスの paint() を呼び出す
        }
}
 

イベントのオブジェクトからイベントの発生したオブジェクトの情報を取り出す ことができます。ここでは、あらかじめ RevNameのオブジェクトを仮定しています。 その repaint()メソッドを呼び出すことで、キャンバスの表示を変更します。

・ 上のアダプタの部分は MouseListener を使って書いてもまったく同じです。 MouseAdapterは MouseListenerについて便宜的に形式的な実装を行った クラスにすぎないからです。 ただし、この場合は5個のメソッドをすべて形式的に実装しないと、 コンパイル時にエラーとなります。


/** マウスの操作を処理する ReverseAdapter のクラス定義 */
import java.awt.*;
import java.awt.event.*;
public class ReverseAdapter implements MouseListener {

   /** マウスがアプレット内に入った時に自動的に呼び出される */
        public void mouseEntered( MouseEvent evt ) {
               RevName rev = (RevName)(evt.getSource());
               rev.stateFlag = true;
               rev.repaint();    // キャンバスの paint() を呼び出す
        }
 
   /** マウスがアプレットの外に出た時に自動的に呼び出される */
        public void mouseExited( MouseEvent evt ) {
               RevName rev = (RevName)(evt.getSource());
               rev.stateFlag = false;
               rev.repaint();    // キャンバスの paint() を呼び出す
        }

   /** マウスボタンが押された時に自動的に呼び出される */
        public void mousePressed( MouseEvent evt ) {
        }
 
   /** マウスボタンが放された時に自動的に呼び出される */
        public void mouseReleased( MouseEvent evt ) {
        }
 
   /** マウスボタンがクリックされた時に自動的に呼び出される */
        public void mouseClicked( MouseEvent evt ) {
        }
}

・ 上のサンプルは、アダプタ(リスナ)のクラスは完全に独立したクラスでしたが、 アダプタのクラスはしばしば innerクラスとして定義されます。 アダプタはその性格上、それぞれのアプリケーション固有の仕事を行うからです。 innerクラスとして定義すると、名前の衝突を防ぐことができる、 元のクラスのフィールドの情報を参照したり引数で渡したりする必要がなくなる、 などのメリットがあります。
また、さらに極端な場合には、リスナをコンポーネントのクラス自身に 実装してしまうこともできます。 上のサンプルの場合ならば、次のような記述になり、 イベント処理のメソッドを含めてすべて単独のクラス内に記述できます。 (ちょうど古いスタイルのイベント処理のようになるわけです。)


/** マウスの操作で表示が反転する RevName のクラス定義 */
import java.awt.*;
import java.awt.event.*;
public class RevName extends Canvas imlements MouseListner {
                       :
                       :
   /** コンストラクタ */
        public RevName() {
               super();
               setSize( 200, 40 );
               addMouseListener( this );  //自分自身をリスナとして登録
        }
                       :
                       :