プログラムソース
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Painter extends Applet{
int px, py, rx, ry;
int n = 0;
Color c1 = new Color(25,25,25);
Color c2 = new Color(39,38,114);
Color c3 = new Color(229,0,30);
Color c4 = new Color(51,96,69);
Color c5 = new Color(229,169,0);
Color c6 = new Color(248,169,0);
Color color[] = {c1,c2,c3,c4,c5,c6};
public void init(){
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
px = e.getX();
py = e.getY();
rx = 0;
ry = 0;
}
});
addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent e){
rx = e.getX();
ry = e.getY();
px = 0;
py = 0;
}
});
addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
Graphics g = getGraphics();
n++;
if(n > 5) n = 0;
switch(n){
case 0 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;黒",60,40); break;
case 1 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;藍",60,40); break;
case 2 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;深紅",60,40); break;
case 3 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;深緑",60,40); break;
case 4 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;柿色",60,40); break;
case 5 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;山吹色",60,40); break;
}
}
});
addMouseListener(new MouseAdapter(){
public void mouseExited(MouseEvent e){
Graphics g = getGraphics();
n++;
if(n > 5) n = 0;
switch(n){
case 0 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;黒",60,40); break;
case 1 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;藍",60,40); break;
case 2 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;深紅",60,40); break;
case 3 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;深緑",60,40); break;
case 4 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;柿色",60,40); break;
case 5 : g.clearRect(20, 30, 150, 20) ;
g.drawString("現在の色;山吹色",60,40); break;
}
}
});
addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
Graphics g = getGraphics();
g.setColor(color[n]);
g.drawLine(px, py, e.getX(), e.getY());
px = e.getX();
py = e.getY();
}
});
}
public void paint(Graphics g){
g.setColor(Color.black);
g.drawString("お絵描きアプレット", 60, 20);
g.drawRect(0, 0, 247, 247);
}
}
実行結果
考察
- 今回作ったのは、マウスをドラッグする事で線を描き、アプレット上でクリック又はアプレットの外にマウスを出すと色が変わるお絵描きアプレットである。
- 1~3行目;パッケージのインポート記述。
- 6行目;pxpyがマウスを押した位置の差表。rxryはマウスを放した時の位置の座標。
- 8~13行目:色の作成。上から、黒、藍、深紅、深緑、柿色、山吹色。
- 15行目:配列に作成した色を入れる。
- 18~25行目:イベント処理その一、マウスのボタンが押された時の処理。
pxに押された位置のx座標を、pyにy座標を入れる。rx.ryを初期化。
- 27~34行目:イベント処理その二、マウスのボタンが離された時の処理。
ボタンが離された時の座標をrx,ryに代入、px,pyは初期化。
- 36~49行目:イベント処理その三、マウスがクリックされたときの処理。
int型変数nをインクリメントする。6より大きくなったら0に戻す。
あとswitch文で今何色にセットされているか表示させる。
- 51~64行目:イベント処理その四、マウスがアプレットから出た時の処理。
マウスがクリックされた時と同様。
- 66~75行目:イベント処理その五。マウスをドラッグする時の処理。
68行目でグラフィックオブジェクト生成。68行目で色の設定。70行目で線を引くメソッド。(px,px)から(e.getX()、e.getY())までの線を引く。
*文法解説*
- イベントとイベントリスナ
イベントとは、アプリケーションのユーザーがGUIコンポーネントを操作する事で、このイベントが通知されるとアプリケーションに実装したイベントリスナが呼び出される。java.awt.eventにはイベント種類別に様々なイベントクラスが用意されている。以下にまとめる。
イベントクラス |
イベントリスナインタフェース |
発生理由 |
ActionEvent |
ActionListener |
メニュー、ボタンの選択等 |
AdjustmentEvent |
AdjustmentListener |
スクロール操作 |
ComponentEvent |
ComponentListener |
コンポーネント状態の変化 |
ContainerEvent |
ContainerListener |
コンポーネントの追加と削除 |
FocusEvent |
FocusListener |
コンポーネントフォーカスの変化 |
InputMethodEvent |
InputMethodListener |
入力媒体によるテキストの変化 |
ItemEvent |
ItemListener |
チェックボックス、リスト選択の変化 |
KeyEvent |
KeyListener |
キー操作 |
MouseEvent |
MouseListener |
マウス操作 |
TextEvent |
TextListener |
テキストエリア、テキストフィールドの変化 |
WindowEvent |
WindowListener |
ウィンドウ状態の変化 |
このイベントリスナとGUIコンポーネントを結びつける仕組みが、イベントデリゲーションモデルと呼ばれるものである。例えばボタンを押すときのイベント処理の過程を考えると、
- 最初にaddActionListene()メソッドを使ってボタンオブジェクトにActionListenerというイベントリスナを登録する。
- イベントリスナとしてアプリケーションにActionListenerインタフェースのactionPerformed()メソッドを実装する。
- ユーザーがボタンを押すとACTION_PERFORMEDを表すActionEVentというイベントが生成される。このイベントによりアプリケーションに実装したactionPerformed()メソッドが呼び出される。
- 結果、actionPerformed()メソッドにActionEventイベント処理が託された事になる。
次にイベントリスナの実装と登録について。まず、イベントリスナを登録するには、
add○○○Listener()
という形式のメソッドを用いる。いかに主なものをまとめた。
イベントリスナを登録するメソッド |
登録されるコンポーネント |
addActionListener |
Button,List,TextField,Timer等 |
addAdjustmentListener |
Scrollbar |
addComponentListener |
Component |
addContainerListener |
Container |
addItemListener |
Checkbox,Choice,List等 |
addMouseListener |
Component |
addMouseMotionListener |
Component |
addWindowListener |
Window |
次にイベントリスナの実装法だが、いくつかの方法がある。
- implementsキーワードでコンテナにイベントリスナインタフェースを実装する。以下に例のプログラムを書く。
public class aptest extends Applet implements ActionListener{
Button b1 = new Button;
public void init(){
add(b1);
b1.addActionListener(this);
}
public void actionPerformed(ActionEVent e){
ここにactionPerformedメソッドの本体を記述
}
}
ただし、この方法だと、メインウィンドウで同じコンポーネントを複数使っている場合には、e.~として区別しなければならない。
- 無名内部クラスを定義する。
add○○Listener()形式のメソッド呼び出し文の引数の中でイベントリスナの実装定義とインスタンス生成をする。以下に例のプログラムを書く。
public class aptest extends Applet {
Button b1 = new Button;
public void init(){
add(b1);
b1.addActionLIstener(
new ActionLIstener(){
public void actionPerformed(ActionEvent e){
ここにactionPerformedメソッドの本体を記述
}
}
);
}
}
- addpterクラスを利用する。
インタフェースを実装して利用する場合、abstract属性のメソッドすべてを実装しない限りインスタンスを生成出来ない。しかし、イベントリスナインタフェースの中には多くのメソッドを持つものがある。それらのメソッドのうち一つしか使わないのに、すべてを実装するには非常に手間がかかって面倒なので、そこで利用されるのがアダプタクラスである。そのようなインタフェースのメソッドをabstract属性でないメソッドとして空実装しているのがアダプタクラスである。このアダプタクラスは中所クラスだが、どれか必要なメソッドのみ実装すれば実体化出来るという特性を持っている。ただし、Javaすべてのイベントリスナインタフェース用にアダプタクラスが定義されている訳ではないので注意。以下にJavaの主なアダプタクラスをまとめた。
アダプタクラス |
対応するインタフェース |
ComponentAdapter |
ComponentListener |
ContainerAdapter |
ContainerListener |
FocusAdapter |
FocusListener |
InternalFrameAdapter |
InternalFrameListener |
KeyAdapter |
KeyListener |
MouseAdapter |
MouoseListener |
MouseMotionAdapter |
MouseMotionListener |
WindowAdapter |
WindowListener |
今回のプログラムではこの方法を使ってイベントリスナの実装を行った。あと、ActionListenerはメソッドが一つしかないので、アダプタクラスは存在しない。