ユーザーの入力を処理する

 Java言語のウィンドウ・システムのパッケージでは、 ユーザーからの入力を「イベント」という概念で取り扱います。 このために Event という専用のクラスがあり、 アプレットにはマウスやキーボードからのイベントを処理する メソッドが用意されています。 それらを利用することで、 ユーザーによるアプレットの操作が可能になります。

マウス操作の6個のメソッド

 ウィンドウ・システムでは、ユーザーはマウスやキーボードなどの 入力装置を使ってアプリケーションを操作します。 ユーザーが行った操作は、「イベント」と呼ばれる情報として アプリケーションに伝えられます。 アプリケーションの側では、常にどんなイベントが来るかを監視し、 発生したイベントに応じて処理を行う必要があります。 Java言語のウィンドウ・システム(awt)では、 Eventクラスのオブジェクトによってイベントの情報を伝えます。 Appletクラスには、マウス、キーボード、キーボード・フォーカスのイベント を処理するためのメソッドが用意されています。 (正確には、 いずれもスーパー・クラスである Componentクラスから継承したものです。) これらのイベント処理のメソッドは、 対応するイベントが発生すると自動的に呼び出される仕組みになっています。 アップレットのプログラムはイベント処理の内容を用意するだけで、 イベント監視のためのループなどは表面には現れません。

まず最も利用されることが多いマウスのイベントから紹介します。 マウスのイベントを扱うため、 Appletクラスには以下の 6個のメソッドが用意されています。

マウスのイベント処理のメソッド
メソッド名 機能
mouseEnter(Event,int,int) マウスのポインタがアプッレトの中に入った時の処理
mouseExit(Event,int,int) マウスのポインタがアプッレトから出た時の処理
mouseDown(Event,int,int) マウスのボタンが押された時の処理
mouseUp(Event,int,int) マウスのボタンが放された時の処理
mouseDrag(Event,int,int) マウスのボタンが押された状態で移動した時の処理
mouseMove(Event,int,int) マウスのボタンが放された状態で移動した時の処理

マウスのイベント処理のメソッドは、すべて boolean型です。 最初の引数は、 発生したイベントの情報を記憶したEventクラスのオブジェクトです。 この内部には、イベントの発生したオブジェクト、 イベントの発生した時刻などの情報が含まれています。 続く2つの int型の数値はイベントが発生した位置の XY座標です。 Appletクラスでは、これらのメソッドの処理の内容は空です。 アプレットのプログラムの中で必要な処理の内容を再定義します。 たとえば、以下のようになります。 処理の最後には、必ず true を返値として返すようにしてください。


 public Boolean mouseDown( Event event, int x, int y ) {

      if( x > 100 )
          repaint();    // paint() を呼び出す

      return true;
 }


メソッドの引数と返値

 イベント処理のメソッドは、 メソッドの型や引数の個数と型が決まっていることに注意してください。 上の例を見てわかるように、 与えられた引数の値は常に利用されるわけではありません。 特に Eventのオブジェクトは利用されるケースの方が少ないでしょう。 Eventの情報で最も重要なのは「何のイベントか?」ということですが、 メソッドが呼び出された段階では既にその識別が済んでいるからです。 Eventの情報を利用するのは、細かい処理に限られます。 しかし、使用しない場合でも形式上書いておく必要はあります。 Java言語では引数の数や型が異なると異なるメソッドと見なされます。 引数を省略してもコンパイル時や実行時にエラーは発生しません。 新しい別のメソッドと解釈されるからです。 しかし、イベントが発生しても期待した処理は呼び出されません。 かえってやっかいなバグを生み出してしまうので注意してください。
 boolean型の返値を返すのも忘れてはいけません。 こちらはコンパイル時に厳密にチェックを受けます。 コンパイル時のエラーを消すためにメソッドの型の方を変えてはいけません。 やはり別の新しいメソッドと解釈され、イベント処理は呼び出されません。

ユーザーが絵を描けるアプレット

 従来の WWWのページは情報の流れが一方向です。 読者はどうしても受動的な存在になってしまいます。 しかしイベント処理を組み込んだアプレットを用いれば、 読者に対して豊富な表現手段を提供することができます。 その可能性を示す例として、簡単なツールを1つ紹介しましょう。 非常に単純なサンプルですが、 このアプレット上には読者がマウスで絵を描くことができます。



import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Event;

/** マウスの操作で絵を描くことができる Paper のクラス定義 */

public class Paper extends Applet {

    /** 描きたい線の両端の座標 */

       protected int x1=0, y1=0, x2=0, y2=0;

    /**
     * アプレットに「白い画用紙」の領域を描く。このアプレットでは、
     * update() を書き換えたため、最初の表示の時にだけ呼び出される。
     */
       public void paint( Graphics g ) {

             g.setColor( Color.white );
             g.fillRect( 0, 0, size().width, size().height );
       }

    /**
     * アプレットにグラフィックを描く。repaint() によって呼び出される。
     * このアプレットでは通常とは異なり、以前の図形のクリアや、
     * paint() の呼び出しを行わない。
     */
       public void update( Graphics g ) {

             g.drawLine( x1, y1, x2, y2 );  // 線を描く
             x1 = x2;
             y1 = y2;
       }

   /** マウスボタンが押された時に自動的に呼び出される。*/

       public boolean mouseDown( Event evt,  int x, int y ) {

             x1 = x;
             y1 = y;

             return true;
       }

   /** マウスボタンが押されたまま移動した時に自動的に呼び出される。*/

       public boolean mouseDrag( Event evt,  int x, int y ) {

             x2 = x;
             y2 = y;
             repaint();      // update() を呼び出す

             return true;
       }
}


 プログラムがコンパイルできたら、 呼び出すための適当な HTMLファイルを用意して 表示を確認してください。


<TITLE>Paper</TITLE>
<H1>
Paper アプレットのサンプル
</H1>
<HR>
<APPLET CODE="Paper.class" WIDTH="400" HEIGHT="300">
</APPLET>

イベント駆動型の処理

 上のプログラムがどのように処理を行うか、 その流れを追ってみましょう。 主要な部分は、 mouseDrag() と update() メソッドの内容です。 マウスのドラッグ操作のイベントが検出されると、 そのたびに mouseDrag() が呼び出されます。 このメソッドに渡される座標 ( x2, y2 ) は、 イベントが検出された時点でのマウス・ポインタの位置です。 その位置を線の「終点」と解釈して update() を呼び出し、 drawLine() を使って線を描きます。 線を描き終わったら、「終点」を次の線の「始点」に置き換えます。
以上の操作を繰り返すことで、マウス・ポインタの動きにしたがって 絵が描かれることになります。 mouseDown() のメソッドは、絵を描き始める点の座標 ( x1, y1 ) を与えます。
 プログラムの処理の流れは、 完全にイベントによってコントロールされている点に注目してください。 このようなプログラムの流れは、「イベント駆動型」と呼ばれます。 ウィンドウ・プログラミングのスタイルの大きな特徴です。 Java言語のアプレットでも、このスタイルでプログラムが書かれることが 前提になっています。 mouseDrag() を呼び出す命令はプログラムの中にはありません。 また、 それらのイベント処理を監視するためのループも プログラムの中に記述する必要はありません。

絵の内容の追加

 このアプレットでは 2つの描画メソッド paint() と update() が、完全に使い分けられています。 デフォルトの内容の update() では、 以前の絵の表示のクリアと paint() の呼び出しが実行されます。 update()を定義し直したので、それらの作業はもはや呼び出されません。 このアプレットでは、paint() は最初に画面に現れた時、 あるいは画面に再登場した時のみ呼び出されます。 repaint() によって呼び出されるのは update() に記述された内容だけです。 update() が呼び出されても以前の絵はクリアされず、次々と追加されます。

アプレットのプログラミングの留意点

 さて、上の例のように Java言語におけるグラフィックのコントロールや イベント処理は、驚くほど簡単です。 半ばパターン化された最低限の記述で、必要な機能を実現することができます。 しかし、その反面落とし穴もあります。 論理的に流れを追っていくだけで、 プログラムを理解したり自由自在に書いたりできるとは限らないのです。 プログラマーは「ブラックボックス化」されたクラスについて、 その固有のルールをきちんと覚えておかなければなりません。
 実際、上のプログラムは mouseDrag() や update() などのメソッドの意味を知らなければ、理解は不可能でしょう。 たとえ文法的な知識は完全であったとしても、 それだけでは どんな振る舞いをするプログラムなのか知ることはできないのです。