応用プログラミング - イベント処理 - イベント : プログラムへの働きかけ (GUI のボタンをクリックする, キーボードよりデータを入力するなど ) イベント処理 ( イベントハンドリング ): イベントに対する応答及びそのプログラム処理 イベントを処理するプログラムは イベントが発生した場合にのみ 呼び出される ( イベントドリブン ) GUI イベント イベント処理のプログラム イベント処理の仕組みと流れ 1ボタンをクリック 2イベントが発生 3イベントがイベント処理のプログラムに渡される イベント処理の概念図 処理 4プログラムがイベントを受け取り処理する処をう イベントソース (GUI) 1 リスナーをソースに登録 イベントリスナー ( イベントを処理するプログラム ) イベント ( イベントオブジェクト ) 処理 2 ソースにアクションをかける 3 イベントが発生 4 イベントがリスナーに渡される 5 リスナーがイベントを受け取り処理を行う プログラム構成を含めた処理の流れ イベント :: イベント処理により状態変化した内容の表すオブジェクト ( クラスは EventObject のサブクラス ) ( イベント ) ソース :: イベントを生成するオブジェクト (GUI のコンポーネントのオブジェクトなど ) ( イベント ) リスナー :: イベントを受け取り, 処理を行なうオブジェクト [ 注意点 ] イベントおよびソース イベントはオブジェクトとして渡される イベントのクラスはアクションの内容によって異なる ( ボタンをクリック, テキストを変更など ) イベントクラスは java.awt.event パッケージに含まれる ( プログラム作成時に import が必要 ) リスナー イベントリスナーはイベント ( の内容, クラス ) によって予め決まっている イベントリスナーはインターフェースとして定義されている イベントリスナーのメソッド ( イベント処理を行うメソッド ) を実装時に全て定義する必要がある ( アダプタークラスを継承する場合は必要なメソッドのみ定義すれば良い 1 )
プログラムの作成では以下の2 点を行なう 1 ( イベント ) リスナー側クラスの定義とそのクラス内のメソッドに処理内容を記述 (1) イベントを受け取るためにリスナーインターフェースの実装 :: ActionListner の実装など (2) イベントの受け取り後の処理 :: actionperformed(actionevent e) など リスナーインターフェースはイベントの種類によって決められている ( 教科書 P150 表 12.1) 2 ( イベント ) ソース側リスナーの登録ソースになるコンポーネント内にリスナーを登録 ::addactionlistner(actionlistner e) など ( 具体例 ) 教科書 P153 リスト 12.1 ボタンのクリック時に発生する ActionEvent の処理 ( 教科書 P153 リスト 12.1) 1 に関する処理 (1) イベントリスナークラスを定義 L4 リスナーインターフェースを実装する ( イベントに応じたリスナーインターフェースの利用 ) ( リスナークラスに ActionListner インターフェースを実装 ) (2) イベント受け取り後の処理を定義 L18 ~25 ActionEvent が起こったときの振る舞いを actionperformed メソッドに記述 Class MyListener implements ActionListener{ // ActionListener public void actionperformed(actionevent e){ // ActionEvent 2 に関する処理イベントリスナークラスの定義 ( イベント ) ソースになるコンポーネントにイベントリスナーを登録する. L11,12 ( 12.1 2 b1.addactionlistener(this) [( ) ( ( ))] 教科書 P153 リスト 12.1 の処理の内容 GUI の作成とイベント処理用プログラムの追加 (1) コンポーネントのインポート (L1~3 ) L2 がイベントコンポーネントのインポート import java.awt.event.*.* (2) イベントリスナーの実装によるサブクラスの作成 (JPanel を継承, ActionListner を実装 ) L4~27 (3) コンストラクタ L7~17 GUI コンポーネントの設定 ( ラベルとボタンの設定 ) L8~10 イベントリスナーの登録 ( ボタンがソースのため, ボタンのオブジェクトのメソッドにより )L11,12 ) GUI のレイアウト L13 コンポーネント ( ボタンとラベル ) を中間コンポーネント ( 自分のオブジェクト ) に貼り付ける L14~16 (4) イベント処理メソッド (actionperformed( )) の定義 L18~25 メソッドの引数に注意 (5) main メソッド ( 省略 :GUI やグラフィックスの場合と同様 ) 2
ButtonEvent1.java 1:/ ボタンの ActionEvent のサンプルプログラム 1 2: 3:import javax.swing.*; 4:import java.awt.*; 5:import java.awt.event.*; 6: 7:class ButtonEvent1 { 8: public static void main(string args[]) { 9: JFrame f = new JFrame("ButtonEvent1"); 10: f.setdefaultcloseoperation(f.exit_on_close); 11: Container c = f.getcontentpane(); 12: JButton b = new JButton("C l i c k!"); 13: 14: // イベントリスナーのインスタンスを作る 15: mylistener1 ml = new mylistener1( ); 16: 17: // ボタンにイベントリスナーを登録する 18: b.addactionlistener(ml); 19: 20: c.add(b); 21: f.pack(); 22: f.setvisible(true); 23: 24: 25: 26:/* イベントリスナー インタフェース を実装して 27: イベントリスナー クラス を定義 */ 28:class mylistener1 implements ActionListener { 29: 30: /* イベント処理メソッドの定義 31: イベントリスナーインタフェースの 32: 抽象メソッドをオーバーライド */ 33: public void actionperformed(actionevent ae) { 34: System.out.println(" ボタンがクリックされました "); 35: 36: 表示例 イベントクラスを呼び出すためコンポーネントを import する [ GUI 作成部分 ] コンテントペインに直接ボタンを貼り付けていることに注意 ボタンの作成 登録のためにリスナーのデフォルトコンストラクタを呼んでいるオブジェクトを作成 ActionListener インターフェースを実装 イベントオブジェクト ( 処理内容によって予め決められている ) イベント処理メソッド ( イベントによって予め決まっている ) 出力結果例 Click E: >java ButtonEvent1 イベント処理の内容を記述 3
[ 応用 ] 下記のようにボタンが 2 つならば 1~3 の変更を行う. 処理結果 ButtonA を 2 回, 続いて ButtonB を押す場合 E: >java ButtonEvent2 Button A がクリックされました Button A がクリックされました Button B がクリックされました ( 変更点 ) 1 12 行目に 2 つのボタンを設定 ( 例 ) JButton ba = new JButton("Button A"); JButton bb = new JButton("Button B"); 2 18 行目に 2 つの各ボタンに対して, イベントリスナーを登録 ( 例 ) ba.addactionlistener(ml); bb.addactionlistener(ml); 3 34 行目に各ボタンに対する処理を記述 ( 例 ) String bname = ae.getactioncommand(); if(bname=="button A") System.out.println("Button A がクリックされました "); else System.out.println(" Button B がクリックされました "); リスナークラスの定義独立したリスナークラスの定義イベントリスナーを自分とは別の独立したクラスにする. 独立性を持たせる ( 欠点 ) ( 例 ) リスナーのクラスとして,OutListener クラスを定義 ActionListener インターフェースをインプリメントする ( どんなクラスも ActionEvent のリスナーになれる ) リスナーのオブジェクト ソースのオブジェクト イベント処理 { ソースのオブジェクトを利用 4
リスナークラスの独立 1://HelloOut.java 2:// リスト 12.4 独立したリスナークラス ( 教科書 p162) 3:import java.awt.*; 4:import java.awt.event.*; 5:import javax.swing.*; 6: 7:class HelloOut extends JPanel{ 8: JLabel label; // ラベル用の変数 9: JButton b1, b2; // ボタン用の変数 10: OutListener listener; 11: HelloOut(){ 12: label = new JLabel(" "); // 最初は何も表示しない 13: b1 = new JButton(" ごあいさつ "); // ごあいさつボタン 14: b2 = new JButton(" 消去 "); // 消去ボタン 15: 16: listener = new OutListener(this); 17: b1.addactionlistener(listener); // イベントリスナーを設定 18: b2.addactionlistener(listener); // イベントリスナーを設定 19: 20: setlayout(new BorderLayout()); // 配置方式の設定 21: add(label, BorderLayout.NORTH); // ラベルを置く 22: add(b1, BorderLayout.CENTER); // ボタンを置くイベントリスナーをソース内に 23: add(b2, BorderLayout.EAST); // ボタンを置く設定 ( イベントリスナーのコンス 24: トラクターの呼び出し引数に自 25: 分 ( オブジェクト ) を設定 ) 26: public static void main(string args[ ]){ 27: HelloOut h = new HelloOut(); //HelloOut のオブジェクトを生成 28: JFrame frame = new JFrame(); //JFrame オブジェクトを生成 29: Container c = frame.getcontentpane(); // フレームの内容表示域を得る 30: c.add(h, BorderLayout.CENTER); // フレームに HelloOut オブジェクトを置く 31: frame.pack(); // フレームを必要最小の大きさにする 32: frame.setvisible(true); // フレームを画面に見せる 33: 34: 35: イベントリスナー 36:class OutListener implements ActionListener{ // イベントリスナー 37: HelloOut hello; 38: public OutListener(HelloOut h){ 39: hello = h; 40: 41: 42: public void actionperformed(actionevent e){ 43: if(e.getsource() == hello.b1){ //b1が押されたら 44: hello.label.settext(" こんちには "); //label に文字列を設定 45: else if(e.getsource() == hello.b2){ //b2 が押されたら 46: hello.label.settext(" "); //labelの文字列を消す 47: 48: 49: コンストラクタ [ イベントソース ] GUI の作成 イベントソースのオブジェクトのコンポーネントにアクセス GUI 5
リスナークラスの内部クラス化 1: // リスト 12.5 内部クラスとしてのリスナークラス ( 教科書 p163) 2:import java.awt.*; 3:import java.awt.event.*; 4:import javax.swing.*; 5: 6:class HelloIn extends JPanel{ 7: JLabel label; // ラベル用の変数 8: JButton b1, b2;// ボタン用の変数 9: InListener listener; 10: HelloIn(){ 11: label = new JLabel(" "); // 最初は何も表示しない 12: b1 = new JButton(" ごあいさつ "); // ごあいさつボタン 13: b2 = new JButton(" 消去 "); // 消去ボタン 14: 15: listener = new InListener(); 16: b1.addactionlistener(listener); // イベントリスナーを設定 17: b2.addactionlistener(listener); // イベントリスナーを設定 18: 19: setlayout(new BorderLayout()); // 配置方式の設定 20: add(label, BorderLayout.NORTH); // ラベルを置く 21: add(b1, BorderLayout.CENTER); // ボタンを置く 22: add(b2, BorderLayout.EAST); // ボタンを置く 23: 24: 25: class InListener implements ActionListener{ // イベントリスナー 26: public void actionperformed(actionevent e){ 27: if(e.getsource() == b1){ //b1が押されたら 28: label.settext(" こんちには "); //labelに文字列を設定 29: else if(e.getsource() == b2){ //b2 が押されたら 30: label.settext(" "); //labelの文字列を消す 31: 32: 33: 34: 35: public static void main(string args[]){ 36: HelloIn h = new HelloIn(); //Hello のオブジェクトを生成 37: JFrame frame = new JFrame();//JFrame オブジェクトを生成 38: Container c = frame.getcontentpane(); // フレームの内容表示域を得る 39: c.add(h, BorderLayout.CENTER);// フレームに Hello オブジェクトを置く 40: frame.pack(); // フレームを必要最小の大きさにする 41: frame.setvisible(true); // フレームを画面に見せる 42: 43: 表示結果例 Hello.java, HelloOut.java, HelloIn.java 共通 HelloIn HelloIn コンストラクタ [ イベントソース ] GUI の作成 イベントリスナーをソース内に設定 ( 内部のクラスでもオブジェクトを作成し, そのオブジェクトを登録する ) イベントリスナー InListener は HelloIn クラスの内部なので label (this.label ) ActionListner HelloIn InListener クラスの作成は不必要である. つまり,actionPerformed メソッドの定義のみで良い. これは Hello.java( リスト 12.1) となる. ごあいさつ ボタンをクリック 消去 ボタンをクリック 6
アダプタークラスリスナーインターフェースが複数のイベント処理メソッドを持つ場合 リスナーインターフェースを実装する場合, 全てのメソッドを定義する必要がある. ( 例 :MouseListener インターフェースでは mousepressed( ), mousereleased( ), mouseclicked( ), mouseentered( ), mouseexited( ) の 5 つを定義する必要がある.) 必要なメソッドだけを定義する. クラス ( 例 :MouseAdopter クラスを継承すると, 必要なクラスのみ定義ればよい. インターフェースが 1 つのメソッドのみの場合はアダプタークラスの利用は意味が無い.) 1:// リスト 12.6 アダプターを使ったマウスリスナー ( 教科書 p164) 2:import java.awt.*; 3:import java.awt.event.*; 4:import javax.swing.*; 5: 6:class AdapterTest extends JPanel{ 7: int x1, y1, x2, y2; 8: AdapterTest(){ 9: setbackground(color.yellow); 10: setminimumsize(new Dimension(250, 250)); 11: setpreferredsize(new Dimension(250, 250)); 12: // addmouselistener(new MyMouse( )); // マウスリスナーを設定 13: MyMouse mm=new MyMouse(); // マウスリスナーを設定 14: addmouselistener(mm); 15: 16: 17: 18: public void paintcomponent(graphics 19: super.paintcomponent(g); 20: g.drawline(x1,y1,x2,y2); 21: 22: 23: class MyMouse extends MouseAdapter{ // 内部リスナークラス 24: public void mousepressed(mouseevent e){ // マウスを押した時の処理 25: x1 = e.getx(); 26: y1 = e.gety(); 27: 28: public void mousereleased(mouseevent e){ // マウスを離した時の処理 29: x2 = e.getx(); 30: y2 = e.gety(); 31: repaint(); // ボタンを離した時 図形を描く 32: 33: 34: 35: public static void main(string args[]){ 36: AdapterTest h = new AdapterTest(); 37: JFrame frame = new JFrame(); 38: Container c = frame.getcontentpane(); 39: c.add(h, BorderLayout.CENTER); 40: frame.pack(); 41: frame.setvisible(true); 42: 43: イベントリスナーの登録 (MyMouse クラスのオブジェクトを引数にして登録する ) 12 もしくは 13&14 と記述する ( イベントリスナーを内部クラスとして設定する場合と同様 ) アダプタークラスの継承 リスナークラスの設定 必要な 2 つのメソッドのみ定義 7
匿名内部クラス ( 無名インナークラス ) ( 特徴 ) 名前を持たない内部クラス クラスの定義とインスタンス ( オブジェクト ) の生成を一つに記述する ( 記述方法 ) new スーパークラス名 ( コンストラクタの引数 ){ 本体 ( 各メソッド ) ; ( 例 ) イベントリスナーでの設定 class MyWindowListener extends WindowAdapter{ public void WindowCloseing(WindowEvent e){ System.exit(0); イベントソースでの設定 ~ イベントリスナーの登録 ~ JFrame f= new JFrame( WindowDemo ); f.addwindowlistener(new MyWindowListener ( )); アダプタークラス リスナーのオブジェクトを登録 一つにまとめるこの部分に無名インナークラスのインスタンスを生成して登録無名インナークラスの利用イベントソースでの設定 f.addwindowlistener(new WindowAdapter ( ){ public void WindowCloseing(WindowEvent e){ System.exit(0); ); MyWindowListener の MyWindowListener クラスは記述しない ) イベントソース側の設定 ( マウスでの処理に利用 ) f.addmouselistener( new mouseadapter( ){ public void mousepressed(mouseevent me){ setbackground(color.red); repaint( ); アダプタークラス ( 本来 メソッドを定義するクラスのスーパークラス ) メソッドの定義 ); public void mousereleased(mouseevent me){ setbackground(color.green); repaint( ); 8
Timeクラスの利用によるアニメーション Timeクラス : 任意の時間が経過した後にアクションイベントを発生させる機能を持つ ( コンストラクタ, メソッドの内容は教科書 p169,170: start は頻繁に利用される ) 一定時間後の処理に利用 ( コンストラクタの引数として設定 ) Time クラスを利用するアニメーション p145 148 MediaTracker Thread Timer クラスの利用により 複数のスレッドを利用する必要が無い一定の時間ごとに静止画を再描画 (repaint) する 1:// リスト 12.7 Timer を使ったアニメーション ( 教科書 p170, 171) 2:import javax.swing.*; 3:import java.awt.*; 4:import java.awt.event.*; 5: 6:class TimerAnimation extends JPanel implements ActionListener { 7: int number = -1; 8: int cell = 20; 9: int interval; 10: Image[] image; 11: MediaTracker tracker; 12: Timer timer; 13: コンストラクタ 14: TimerAnimation() { 15: // イメージのロード 16: Toolkit toolkit = Toolkit.getDefaultToolkit(); 17: tracker = new MediaTracker(this); 18: image = new Image[cell]; 19: for (int i = 1; i <= cell; i++) { 20: image[i-1] = 21: toolkit.getimage("rabbit/rabbit" + i + ".gif"); 22: tracker.addimage(image[i-1], 0); 23: 24: 25: interval = 150; // 描画の間隔 ( ミリ秒 ) 26: timer = new Timer(interval, this); // タイマーの生成 27: timer.setinitialdelay(0); // すぐに始める 28: timer.setcoalesce(true); // イベントをまとめる 29: 30: setbackground(color.white); // パネルの背景色 31: 32: tracker.waitforall(); // ロードを開始 33: catch(interruptedexception e){ return; 34: startanimation(); // アニメーションの開始 35: 36: 37: public synchronized void startanimation() { 38: if (!timer.isrunning()) { 39: timer.start(); // アニメーションの開始 40: 41: 42: 43: public synchronized void stopanimation() { 44: if (timer.isrunning()) { 45: timer.stop(); // アニメーションを止める 46: 47 9 Timer のオブジェクト timer はインスタンス変数として設定しているのでクラス内の全メソッドで利用可 画像データの登録 Timer クラスのコンストラクタの呼び出しと時間の設定 Timer クラスに関する初期設定 ( オブジェクトのメソッドにより設定 ) timer が動いていなければ 動かす と言う処理
48: 49: public void actionperformed(actionevent e) { // アクションイベント処理 50: number++; // 次に表示するイメージの通し番号 51: repaint(); // 描画 イベント処理部 52: 一定時間経過ごとに 53: 54: public void paintcomponent(graphics g) { 55: super.paintcomponent(g); // 背景の描画 56: int x = getwidth( )/2-30;// ウィンドウのほぼ中央にイメージを表示 57: int y = getheight( )/2-30; 58: try { 59: g.drawimage(image[number%cell], x, y, this); 60: catch (ArrayIndexOutOfBoundsException e) { return; 61: //numberが-1 の時に描画が呼ばれた時の例外処理 62: 63: 64: public static void main(string[] args) { 65: JFrame f = new JFrame("Timer Animation"); 66: TimerAnimation anime = new TimerAnimation(); 67: f.getcontentpane().add(anime, BorderLayout.CENTER); 68: f.setsize(new Dimension(100, 100)); 69: f.setvisible(true); 70: 71: number を増やし,repaint() する Repaint 毎に PaintComponent が呼び出される number は 0 から無限に増え続けるので cell で割ったあまりを利用 ウインドウのアイコン化時のアニメーションの停止と再開アニメーション実行時中にウィンドウをアイコン化した場合 アニメーションを停止する ウィンドウリスナーを設定 ( イベント処理の必要性 ) ( 上記のプログラムで,)TimerAnimation クラスの内部クラスとして, WindowAdapter クラスのサブクラスを定義 アイコン化するため (Window に対するイベントのため )JFrame に対してウィンドウリスナーを設定 // class WindowOpe extends WindowAdapter { public void windowclosing(windowevent e) { System.exit(0); public void windowiconified(windowevent e) { stopanimation(); public void windowdeiconified(windowevent e) { startanimation(); public static void main(string[] args) { JFrame f = new JFrame("Timer Animation"); TimerAnimation anime = new TimerAnimation( ); f.addwindowlistener(anime.new WindowOpe( )); class A{ class B{ // 内部クラス TimerAnimation クラスの内部クラスとして定義されるイベントリスナー JFrame のオブジェクトにリスナーを設定 内部クラスのオブジェクトを設定するため, 外の クラスのオブジェクト anime から直接に内部クラスのコンストラクタを呼んで作成している クラス B のオブジェクト b を作成するには A a = new A( ); B b = a.new B( ); 10 と することと同様
応用プログラミング 2001/10/31 教科書 P153-154 リスト 12.1 こんにちはプログラム クラス Hello はソースとリスナーな混在したプログラムとなっている. // リスト 12.1 こんにちはプログラム (Hello.java) 1:import java.awt.*; 2:import java.awt.event.*; 3:import javax.swing.*; 4:class Hello extends JPanel implements ActionListener{ 5: JLabel label; // ラベル用の変数 6: JButton b1, b2;// ボタン用の変数 7: Hello( ){ イベントクラスを呼び出すためコンポーネントを import する リスナーの登録コンテントペインに 8: label = new JLabel(" "); // 最初は何も表示しない直接ボタンを貼り付 9: b1 = new JButton(" ごあいさつ "); // ごあいさつボタンけていることに注意 10: b2 = new JButton(" 消去 "); // 消去ボタン 11: b1.addactionlistener(this); // イベントリスナーを設定 12: b2.addactionlistener(this); // イベントリスナーを設定 13: setlayout(new BorderLayout()); // 配置方式の設定 14: add(label, BorderLayout.NORTH); // ラベルを置く 15: add(b1, BorderLayout.CENTER); // ボタンを置く 16: add(b2, BorderLayout.EAST); // ボタンを置く 17: 18: public void actionperformed(actionevent e){ 19: if(e.getsource() == b1){ //b1 が押されたら 20: label.settext(" こんにちは "); //label に文字列を設定 21: 22: else if(e.getsource() == b2){ //b2 が押されたら 23: label.settext(" "); //label の文字列を消す 24: 25: 26: 27: public static void main(string args[]){ リスナーのために ActionListner インターフェースを実装 [GUI 作成部分 ] イベント処理のためのメソッドイベント処理の内容を記述 28: Hello h = new Hello(); //Hello のオブジェクトを生成 29: JFrame frame = new JFrame("Hello"); //JFrame オブジェクトを生成 30: Container c = frame.getcontentpane(); // フレームの内容表示域を得る 31: c.add(h, BorderLayout.CENTER); // フレームに Hello オブジェクトを置く 32: frame.pack(); // フレームを必要最小の大きさにする 33: frame.setvisible(true); // フレームを画面に見せる 34: 35: イベントのオブジェクト 初期画面 ごあいさつ をクリック 消去 をクリック