応用プログラミング 第6回


この授業の目的

対話的(インタラクティブ)なアプリケーションを書くためには,マウスの操作を反映させることが必要となります.この授業では,マウスやキーボードを使ったイベント処理を修得します.これまでの授業の内容を使えば,プログラミング課題に取り組むことができますので各自取り組んで下さい.


出席メール

出席メールで「授業中の課題の実施」を確認します.メールを出した時刻,PCの場所(アドレス)を確認します.

to:jhoshino@esys.tsukuba.ac.jp
subject: 応用プログラミング 第6回.氏名,学籍番号
本文: なし(書かなくて結構です)

 


理論

JAVAにおけるイベントの扱い

JAVAではユーザーからの入力のことを「イベント」という概念で取り扱います.プログラムの処理は、 ユーザーの操作によって発生するイベントを中心にして処理されます.このようなスタイルは、「イベント駆動型」と呼ばれます.ウィンドウ上のアプリケーションは, 最初にまずデータの生成など必要な準備を行いますが, その後はイベントを受け付けるための無限ループに入ります. 目的とするイベントを検出すると,それに応じてあらかじめ用意された処理をします.例えば,「マウスボタンのクリック」を検出すると,「色の変更」などの処理を行うように書くことができます.

JAVAの特徴として,イベントを検出する機能と,イベントが起きたときに実行する機能を分離していることが挙げられます.具体的には,ListnerとAdapterというクラス群がイベントを検出する機能を担当します.これらのクラス群を継承して,個々のアプリケーションでイベントが起きたら何を実行するかを記述します.例えば,ゲームを作る場合は,マウスの動きやボタンの操作によって,キャラクタの動作を変更する機能などを実装します.

後でもう一度説明しますが,Listnerはインターフェースで,Adapterはクラスです.AdapterクラスはListnerインターフェースを継承してるだけですので,中身は同じ機能だと考えて良いと思います.クラスとインターフェースという違いから,プログラムを書く際の使われ方が違ってきます.


MotionListenerを用いたマウスイベントプログラム

JAVAでイベントを扱うプログラムを書くのは簡単で,MouseListener, MouseMotionListenerなどのインタフェースを継承するだけで,イベントに応じた機能を書くことができるようになります.下のサンプルプログラムにあるように,アプレットへのマウスの入出やドラッグなどのマウスの状態やボタンの操作によって,特定のメソッドが自動的に呼び出されるようになっています.これらのメソッドに機能を実装するだけで,対話的なアプリケーションを書くことができます.

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



public class MouseEvents extends Applet implements MouseListener,MouseMotionListener{
  private int oldx = 0,oldy = 0;
  public void init(){
    setBackground(Color.lightGray); //背景の色の設定
    addMouseListener(this);       //自分自身をリスナとして登録
    addMouseMotionListener(this);
  }


  //MouseListenerインタフェース
   //インタフェースで定義されている関数を全て書く必要があります
   //使わないメソッドも書かなくてはいけません.

  public void mouseClicked(MouseEvent e){} //マウスボタンがクリックされた時に自動的に呼び出される 
  public void mouseEntered(MouseEvent e){}  //マウスがアプレット内に入った時に自動的に呼び出される
  public void mouseExited(MouseEvent e){}   //マウスがアプレットの外に出た時に自動的に呼び出される
  public void mousePressed(MouseEvent e){   //マウスボタンが押された時に自動的に呼び出される 
        oldx = e.getX();
        oldy = e.getY();
  }
  public void mouseReleased(MouseEvent e){}  //マウスボタンが放された時に自動的に呼び出される


  //MouseMotionListenerインタフェース
  public void mouseDragged(MouseEvent e){  //マウスをドラッグした時に自動的に呼び出される
        Graphics g = getGraphics();
        g.setColor(Color.black);
        g.drawLine(oldx,oldy,e.getX(),e.getY());
        oldx = e.getX();
        oldy = e.getY();
        g.dispose();
  }
  public void mouseMoved(MouseEvent e){}
}

MouseAdapterクラスを用いたマウスイベントプログラム

上記の例では,インターフェースを継承してマウスイベントを処理しましたが,インターフェースを利用すると使わないメソッドまで書かないといけません.MouseAdapterクラスを使うことで,必要なメソッドだけ定義すれば良くなります.但し,インターフェースは複数継承できるのに対して,クラスは一つしか継承できないという制約がありますので,Appletクラスと同時に継承することができません.そのため,イベントを処理するためのクラスを別途作る必要があります.

/*
  MouseAdapterDemo.java
*/
import java.applet.*;
import java.awt.*;
import java.awt.event.*;




public class MouseAdapterDemo extends Applet { //MouseAdapterクラスを同時に継承することはできません.

  public void init() {
    setBackground(Color.green);
    addMouseListener(new MyMouseAdapter(this));   //自分自身をリスナとして登録
  }
}


class MyMouseAdapter extends MouseAdapter {  //上記の例と比較して,継承の仕方の違いを確認して下さい.
  MouseAdapterDemo mad;

  public MyMouseAdapter(MouseAdapterDemo mad) {
    this.mad = mad;
  }

  public void mousePressed(MouseEvent me) { //マウスボタンが押された時に自動的に呼び出される 
    mad.setBackground(Color.red);
    mad.repaint();
  }

  public void mouseReleased(MouseEvent me) { //マウスボタンが放された時に自動的に呼び出される
    mad.setBackground(Color.green);
    mad.repaint();
  }
}

無名インナクラスを用いたマウスイベント

Adapterクラスを使うと使わないメソッドを定義しなくても済むようになりますが,Appletクラスと同時に継承できなくなるため,イベント処理用のクラスと別に書かないといけないという弊害もあります.そこで,「インナクラス」という機能を使うことが多くあります.インナクラスとは,クラスの中にクラスを定義することです.「無名インナクラス」はインナクラスの記述を更に省略したもので,スーパークラスの名前を書くだけでメソッドを定義することができます. 無名インナクラスを用いることで無駄なクラスを省いてコードが長くなるのを防ぐのに役立ちます.

仕組みは複雑に見えますが,実用的にはaddMouseListener(new MouseAdapter())あるいはaddMouseMotionListener(new MouseMotionAdapter())の中に,mousePressed, mouseDraggedなどのイベントごとの処理を書くだけで,インタラクティブなグラフィクスを書くことができます.

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





public class MouseInnerSample extends Applet{
  private int oldx = 0,oldy = 0;


  public void init(){
    setBackground(Color.lightGray);


    addMouseListener(new MouseAdapter(){       //無名インナクラスのスーパークラスの名前
      public void mousePressed(MouseEvent e){  //メソッドを定義する
        oldx = e.getX();
        oldy = e.getY();
      }
    });


    addMouseMotionListener(new MouseMotionAdapter(){
      public void mouseDragged(MouseEvent e){
        Graphics g = getGraphics();
        g.setColor(Color.black);
        g.drawLine(oldx,oldy,e.getX(),e.getY());
        oldx = e.getX();
        oldy = e.getY();
        g.dispose();
      }
    });
  }
}

ここではコンパイルするとMouseInnerSample.classに加えて
MouseInnerSample$1.class,MouseInnerSample$2.classというclassファイルができます.

無名インナクラスを用いたキーイベントの例

上記の例と同じように無名インナクラスを使っていますが,今度はキー入力を検出して描画します.


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



public class KeyEventDemo extends Applet{
  private int LPX = 100,LPY = 100,x = 100,y = 100;
  public void init(){
    setBackground(Color.lightGray);


    addKeyListener(new KeyAdapter(){       //スーパークラスのKeyAdapterクラスを指定
      public void keyPressed(KeyEvent e){
        switch(e.getKeyCode()){
          case KeyEvent.VK_UP     :y = LPY-20;break;  //矢印キーを検出
          case KeyEvent.VK_DOWN   :y = LPY+20;break;
          case KeyEvent.VK_LEFT   :x = LPX-20;break;
          case KeyEvent.VK_RIGHT  :x = LPX+20;break;
        }
        Graphics g = getGraphics();
        g.setColor(Color.black);
        g.drawLine(LPX,LPY,x,y);
        LPX = x;
        LPY = y;
        g.dispose();
      }
    });
  }
}

ボタンのサンプルプログラム

ここでは「ボタン」と「ラベル」の機能を確認します.「ボタン」は名前からも想像できると思いますが,押しボタンの外観をシミュレートしたものです.「ラベル」は,GUI上に表示される文字列です. メソッド名と詳しい機能については,教科書を参考にして下さい.下の例では,getActionCommandでボタン上の文字列を取得して,setTextメソッドでテキストを描画します.


/*
	ButtonEvents.java
*/
import java.applet.*;
import java.awt.*;
import java.awt.event.*;



public class ButtonEvents extends Applet implements ActionListener {
  Label label;

  public void init() {
    Button b1 = new Button("Apple");
    b1.addActionListener(this);
    add(b1);
    Button b2 = new Button("Banana");
    b2.addActionListener(this);
    add(b2);
    Button b3 = new Button("Orange");
    b3.addActionListener(this);
    add(b3);
    label = new Label("                  ");
    add(label);
  }

  public void actionPerformed(ActionEvent ae) {
    label.setText(ae.getActionCommand());
  }
}

無名インナクラスを用いたボタンの作成


マウスイベントやキーイベントと同様にAWTコンポーネントにおいても無名インナクラスを用いることができます.

/*
  ButtonEventsEx.java 無名インナクラスを用いた例

*/



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

public class ButtonEventsEx extends Applet{
  Label label;
  int i;
  public void init() {
    i = 0;
    Button b = new Button("Count");
    b.addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent ae){
        Graphics g = getGraphics();
        g.setColor(Color.white);
        Dimension d = getSize();
        g.fillRect(0, 0, d.width, d.height);
        g.setColor(Color.black);
        g.drawString("Count "+(i++),20,20);
        g.dispose();
      }
    });
    add(b);
  }
}

実習

1)無名インナクラスを用いたマウスイベントとキーイベントの利用例をコンパイルして,動作を確認して下さい.

2)ボタンのサンプルプログラムをコンパイルして動作を確認して下さい.

 


練習問題

MouseInnerSample.javaを拡張して,各自好きな機能を追加して下さい.例えば,

提出先のアドレスはjhoshino@esys.tsukuba.ac.jpです.Subject欄に「応用プログラミング 第6回課題,氏名,学籍番号」を書いて下さい.本文にソースコード,実行結果,考察を記載して下さい.

締め切りは次の授業の開始時まで.ソースコードはメール本文へのコピーあるいは添付どちらでも結構です.


参考資料:JAVAアプレットの実行方法の復習

まず,次のようなプログラムを作ったとします.

import java.awt.Graphics;
import java.applet.Applet;
public class HelloWorldApplet extends Applet {
  public void paint(Graphics g) {
  g.drawString("Hello world!", 50, 25);
 }
}


次のような手順でAppletを実行します.

 

1.HTMLファイルを作成する方法


1) コンパイルする.

% javac HelloWorldApplet.java

2) htmlファイルを以下のように作成する.

htmlファイルの名前はなんでも良い.emacs等のエディタで拡張子を .html として保存する.ただし APPLET CODE = "コンパイルしてできたクラス名(.classは必要ない)"と書くこと.ここではHelloWorldApplet.htmlとして保存したとする.

<HTML><HEAD><TITLE>HelloWorld.java</TITLE></HEAD>
<BODY><H1>HelloWorld.javaのテスト</H1><HR>
<APPLET CODE="HelloWorldApplet" WIDTH=200 HEIGHT=30></APPLET>
</BODY></HTML>

3) appletviewer で実行するか,netscapeから開く.

appletviewerで実行する場合

% appletviewer HelloWorldApplet.html

上記の場合HelloWorldApplet.class,HelloWorldApplet.htmlファイルを同じディレクトリに置いておかなければ実行できない.

 

2.クラスファイルにアプレットタグを書く方法


import とpublic classの間にコメント文としてアプレットタグを書いた場合は,HTMLファイルを作らなくてもappletviewerで実行することができます.

import java.awt.Graphics;
import java.applet.Applet;
/*
  <APPLET CODE="HelloWorldApplet" WIDTH=200 HEIGHT=30>
  </APPLET>
*/

public class HelloWorldApplet extends Applet {
 public void paint(Graphics g) {
  g.drawString("Hello world!", 50, 25);
 }
}

1. コンパイルする.
% javac HelloWorldApplet.java

2. appletviewer で実行する.
% appletviewer HelloWorldApplet.java

上記の場合HelloWorldApplet.class,HelloWorldApplet.javaファイルを同じディレクトリに置いておかなければ実行できない.