2002 -0711 ver 1.00 発行予定 -0714 ver 1.01 誤字修正 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃.&&&& **** %%%%. JavaScript&Javaで目指そう!基本情報技術者試験 ┃ ┃&&&&&&******%%%%%% 執筆&編集 斎藤末広 suehiro@he.mirai.ne.jp ┃ ┃'&┃&''*┃*''%┃%' 発行 江口昌宏 jmaga@yscon.co.jp ┃ ┗━┻━━┻━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ★解除・登録 広告募集:http://www2.odn.ne.jp/~egu33/jmaga/java-maga.html ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 第22号 2002/07/11 イベント駆動(くどう)型プログラム(GUI) ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ プログラムを作成する上での注意事項: Windows98SE, SDK(JDK) 1.3.1,IE 5.5 を前提としています。 拡張子を表示するに設定してください。 ------------------------------------------------------------------------ ▼ GUI ディスプレイ上に,ボタンとかテキスト枠などの絵を出して,それを利用しな がら,コンピュータとやりとりするやり方を,GUI(Graphics User Interface)と いいます。この号では,その GUI の簡単な例を勉強しましょう。 GUI では,マウスやキーボードを利用しますが,マウスを押したとか,キーを 押したという単位では無く,ボタンを押した,文字列の入力がされたと,認識さ せるレベルがすこし人間よりの単位になります。そのため,前回まで扱った, マウスやキーボードのイベント処理を低レベルイベント処理といい,GUIの部品 単位のイベント処理は,高レベルイベント処理といいます。 この号では,GUI の代表であるボタンを利用したプログラムをみていきましょう。 ------------------------------------------------------------------------ ▼ マウスクリックからボタンクリック 今回は,ボタンがクリックされたときの仕事のやり方を勉強します。 ボタンもマウスでクリックするのが普通ですが,今回は,「マウスでクリック」 を考えずに,「ボタンがクリック」されたと認識するレベルをあげて,「ボタ ンがクリックされた」ときの処理を考えます。 まず,第21号で扱った,イベント処理の典型のマウスクリックのプログラムを 復習をかねて見てみましょう。 例 j20-01 xSmpEvent01.java ソース http://www.yscon.co.jp/j/java/jmaga/j20/xSmpEvent01.java 動作 http://www.yscon.co.jp/j/java/jmaga/j20/xSmpEvent01.htm 説明がしやすいように,行番号を付いています。 1: import java.applet.Applet; 2: import java.awt.Graphics; 3: import java.awt.Image; 4: import java.awt.event.MouseAdapter; 5: import java.awt.event.MouseEvent; 6: 7: public class xSmpEvent01 extends Applet { 8: 9: Image ximg; 10: int x, y; 11: 12: MouseAdapter xia = new MouseAdapter(){ 13: public void mouseClicked(MouseEvent xmouse){ 14: x = xmouse.getX(); 15: y = xmouse.getY(); 16: repaint(); 17: } 18: }; 19: 20: public void init(){ 21: ximg = getImage(getDocumentBase(),"img01.gif"); 22: addMouseListener(xia); 23: } 24: 25: public void paint(Graphics xg){ 26: xg.drawImage(ximg, x, y, this); 27: } 28: } このプログラムは,マウスのクリックしたところに画像を移動します。これを ボタンを押したら,画像が移動にするに変更します。できあがったものは,以下 で確認できます。 例 j22-01 xSmpGUI01.java ソース http://www.yscon.co.jp/j/java/jmaga/j22/xSmpGUI01.java 動作 http://www.yscon.co.jp/j/java/jmaga/j22/xSmpGUI01.htm ------------------------------------------------------------------------ ▼ 利用するクラス マウスクリックのサンプル xSmpEvent01.java で import するクラスを見ま しょう。マウス関連は,次の2つでした。 4: import java.awt.event.MouseAdapter; 5: import java.awt.event.MouseEvent; MouseAdapter クラスは,マウスのイベントをプログラム本体に代わって受付け, 関連の仕事をしてくれるマウス取次係でした。ボタンの場合は,ボタン動作反応 係である,ActionListenerクラスもどきに登場してもらいます。「クラスもどき」 は,正式には,interface といいます。interface は,別の号で解説をします。 MouseAdapter は,以後,マウス係,ActionListener は,ボタン係と呼ぶことに します。 MouseAdapter → ActionListener 5 行目で import されている MouseEvent クラスは,プログラムの中では,ず ばりマウスを指しました。今回はボタンを表す,Button クラスとその Button クラスの裏方で,ボタンが押されたかどうかのセンサとして働く黒子の ActionEvent クラスが必要になります。 マウスのときは,マウスカーソルがすでに存在してましたが,ボタンの場合は, プログラム内で意図的に表示します。そのため,表示を担当する Button クラス が必要と考えるとわかりやすいですね。 (マウス) → Button MouseEvent → ActionEvent となります。 変更前 1: import java.applet.Applet; 2: import java.awt.Graphics; 3: import java.awt.Image; 4: import java.awt.event.MouseAdapter; 5: import java.awt.event.MouseEvent; 変更後 1: import java.applet.Applet; 2: import java.awt.Graphics; 3: import java.awt.Image; n 4: import java.awt.event.ActionListener; n import java.awt.Button; n 5: import java.awt.event.ActionEvent; 行番号は,変更前の番号をそのまま残しています。n があるところは,新しく なったところです。 ------------------------------------------------------------------------ ▼ プログラム宣言部は, 次の部分はどうでしょうか。 変更前 7: public class xSmpEvent01 extends Applet { 8: 9: Image ximg; 10: int x, y; 当然,本体のプログラム名(クラス名)は変えましょう。xSmpGUI01 としましょ う。このプログラムが ボタン等のGUI部品を利用したサンプルの基本になります。 画像の表示は同じようにしますので,9, 10 行目はそのままです。マウスは, 最初から表示されていましたが,今回は表示用のボタンを表示するので,それを 用意しておく要があります。 xSmpEvent01 → xSmpGUI01 ボタン生成 ボタンの生成は, Button xbt01 = new Button("←"); Button xbt02 = new Button("→"); このように生成すると,ボタンの表面には,矢印キーが表示されて,このボタンを おすと,左,右に移動するのだなと使用者に示すことができます。 変更後 n 7: public class xSmpGUI01 extends Applet { 8: 9: Image ximg; 10: int x, y; n Button xbt01 = new Button("←"); // 表ボタン生成 n Button xbt02 = new Button("→"); ------------------------------------------------------------------------ ▼ イベント係(マウス係,ボタン係)は マウス係の仕事内容はどの様に書いたでしょうか。 変更前 12: MouseAdapter xia = new MouseAdapter(){ 13: public void mouseClicked(MouseEvent xmouse){ 14: x = xmouse.getX(); 15: y = xmouse.getY(); 16: repaint(); 17: } 18: }; マウス係は,ボタン係に替わります。ボタン係は,ActionListener でしたので。 MouseAdapter → ActionListener mouseClicked に対応するのは,actionPerformed というものが用意されてい ます。これは,「ボタンが押されたとき」の仕事を表す名前になります。 mouseClicked → actionPerformed 左に移動するボタン,右に移動するボタンとボタンは,2つあり,それぞれに 対応する,ボタン係をおきます。xia は,xia01 と xia02 としましょう。 xia → xia01, xia02 xia01 ボタンが押された時は,x = x - 10 で左に移動します。xia02 ボタンが 押された時は,x = x + 10 で右に移動するとしますので, x = xmouse.getX() → x = x + 10 と x = x -10; 整理すると,変更後は, n12: ActionListener xia01 = new ActionListener(){ n13: public void actionPerformed(ActionEvent xbs){ n14: x = x - 10; 16: repaint(); 17: } 18: }; n n12: ActionListener xia02 = new ActionListener(){ n13: public void actionPerformed(ActionEvent xbs){ n14: x = x + 10; 16: repaint(); 17: } 18: }; となります。同じ行番号が登場しますが,これは前のプログラムとの対応づけを しているだけです。 ------------------------------------------------------------------------ ▼ init() 定義 アプレットが開始されるにあたっての初期化のところは 変更前 20: public void init(){ 21: ximg = getImage(getDocumentBase(),"img01.gif"); 22: addMouseListener(xia); 23: } 同じ画像を同じように使用しますので,21 行目はそのままです。 キーボードの矢印キーで画像を移動した,xSmpKeyEvent.java のプログラム と同様に,x, y の位置をボタンで,増減させますので,最初の位置を,(0,0)と して,初期化で設定しておきます。 x = 0; y = 0; 22 行目の addMouseListener は,addActionListener に変わります。xia01,xia02 を ボタン係,自分の召使いにします。 addMouseListener(xia) → xbt01.addActionListener(xia01) xbt02.addActionListener(xia02); マウス係(MouseListener)は,プログラム本体の召使いになります。ボタン係は, プログラム本体では無く,ボタンの召使いになるので,xbt01. とかが前について います。 ボタンの生成は,宣言部で, Button xbt01 = new Button("←"); Button xbt02 = new Button("→"); と生成されていました。この生成(new)では,主記憶上にボタンを生成するだけで す。画面に載せるためには,本体のプログラムに add しておく必要があります。 init() の中でやっておきます。 add(xbt01); add(xbt02); init() は,以下のようになりました。 20: public void init(){ 21: ximg = getImage(getDocumentBase(),"img01.gif"); n x = 0; y = 0; n n add(xbt01); n add(xbt02); n n22: xbt01.addActionListener(xia01); n xbt02.addActionListener(xia02); n n23: } ------------------------------------------------------------------------ ▼ paint() 定義 表示されるものを見てみましょう。 変更前 25: public void paint(Graphics xg){ 26: xg.drawImage(ximg, x, y, this); 27: } これはまったくこの通りでいいです。 ------------------------------------------------------------------------ ▼ マウスイベントとボタンイベントの違い マウスイベント処理とボタンイベント処理の違いをここで,再度,比較しなが ら整理しましょう。 ------------------------------------------------------------------------- ボタン マウス ========================================================================= クラス 表 Botton なし 黒子 ActionEvent MouseEvent (裏ボタン,センサーとして働く) 取次係 ActionListener MouseAdapter 仕事名 actionPerformed(ActionEvent xbs) mouseClicked(MouseEvent xmouse) 取次係 表ボタン名.addActionListener(取次係名) addMouseListener(取次係名) を雇う 表示の new Button("表示文字列")で生成後 自動的表示 仕方 add(表ボタン名) ------------------------------------------------------------------------ ------------------------------------------------------------------------ ▼ 完成したプログラムは 以下の登場人物を想定してコメントを入れます。 主人公 xSmpGUI01 (表)ボタン xbt01, xbt02 ( Buttonの分身) ボタン係 xia01, xia02 ( ActionListenerの分身 ボタンセンサ(裏ボタン) xubt ( ActionEventの分身) ボタンは表ボタンと裏ボタン(センサ)に分かれます。表ボタンは,ボタンの 形をしています。表ボタンが自分の係(ボタン係)を決めます。そのボタン係が, 裏ボタン(センサ)を表ボタンの下にセットして,センサから押されたどうかを 聞きます。押されたら,ボタン係が仕事をします。 1: import java.applet.Applet; 2: import java.awt.Graphics; 3: import java.awt.Image; 4: import java.awt.event.ActionListener; // ボタン係 5: import java.awt.Button; // ボタン(表ボタン,見た目を作る) 6: import java.awt.event.ActionEvent; // ボタンセンサ(裏ボタン) 7: 8: public class xSmpGUI01 extends Applet{ 9: 10: Image ximg; 11: int x, y; 12: Button xbt01 = new Button("←"); // 表ボタン生成 13: Button xbt02 = new Button("→"); 14: 15: ActionListener xia01 = new ActionListener(){ //ボタン係01 16: public void actionPerformed(ActionEvent xbs){ //ボタンセンサ 17: x = x - 10; //ボタン係01のやる仕事 18: repaint(); 19: } 20: }; 21: 22: ActionListener xia02 = new ActionListener(){ //ボタン係02生成 23: public void actionPerformed(ActionEvent xbs){//ボタンセンサ 24: x = x + 10; //ボタン係02のやる仕事 25: repaint(); 26: } 27: }; 28: 29: public void init(){ 30: ximg = getImage(getDocumentBase(),"img01.gif"); 31: x = 0; y = 0; 32: 33: add(xbt01); //表ボタンを本体プログラムの画面に貼付 34: add(xbt02); 35: 36: xbt01.addActionListener(xia01); //表ボタンが自分のボタン係を任命 37: xbt02.addActionListener(xia02); 38: 39: } 40: 41: public void paint(Graphics xg){ 42: xg.drawImage(ximg, x, y, this); //画面を表示 43: } 44: } ------------------------------------------------------------------------ ▼ 個別法と共通法 xSmpGUI01.java のプログラムで, 13: ActionListener xia01 = new ActionListener(){ //ボタン係01 14: public void actionPerformed(ActionEvent xbs){//ボタンセンサxbs 15: x = x - 10; //ボタン係01のやる仕事 16: repaint(); 17: } 18: }; 19: 20: ActionListener xia02 = new ActionListener(){ //ボタン係02生成 21: public void actionPerformed(ActionEvent xbs){//ボタンセンサxbs 22: x = x + 10; //ボタン係02のやる仕事 23: repaint(); 24: } 25: }; は,xia01 と xia02 にそれぞれにほぼ同じ記述が繰り返されています。一つに まとめることで,今後の拡張のときの手間が少なくなりそうです。共通なところを できるだけ一つにまとめることを,共通化,それを利用したプログラムの書き方を 共通法とよび,それぞれ個別に書いていくことを,個別化,個別法と呼ぶことにし ます。このところを共通化に挑戦してみることにします。 プログラムの中身は,ActionListener クラスもどき(正式名はinterface)から,それぞれ分身(インスタンス)である,xia01,xia02 を生成しました。その生成のさいに, ActionEvent クラスもどきがもともと持っている仕事(actionPerformed)をそれ ぞれ,上書き定義をしました。 ここで,もともとの ActionListener で,+10 したり,-10 して,repaint()を と定義してあれば, ActionListener xai01 = new ActionListener(); ActionListener xai02 = new ActionListener(); とするだけでよかったわけです。共通化が可能になります。 では,ここで,ActionListener クラスもどきの中に,+10 したり,-10 して, repaint() を組み込むことに挑戦しましょう。 Listener は,もともと awt の中で定義されていますので,自分で直接そ れをいじるのはよくありません。このプログラムの中で,定義しなおすことに します。その際,同じ名前ではいけませんので,名前を変えます。ActionListener は, ボタン係でしたので,xButtonAdapter にしてしまいましょう。 自分で,クラスもどきを定義し直すには,次のように変更します。 変更前 12: Button xbt01 = new Button("←"); // 表ボタン生成 13: Button xbt02 = new Button("→"); 14: 15: ActionListener xia01 = new ActionListener(){ //ボタン係01生成 16: public void actionPerformed(ActionEvent xbs){ 17: x = x - 10; //ボタン係01のやる仕事 18: repaint(); 19: } 20: }; 21: 22: ActionListener xia02 = new ActionListener(){ //ボタン係02生成 23: public void actionPerformed(ActionEvent xbs){ 24: x = x + 10; //ボタン係02のやる仕事 25: repaint(); 26: } 27: }; 変更後 12: Button xbt01 = new Button("←"); // 表ボタン生成 13: Button xbt02 = new Button("→"); 14: n15: class xButtonAdapter implements ActionListener{ n16 public void actionPerformed(ActionEvent xbs){ n if (xbs.getSource() == xbt01){ 17: x = x - 10; //ボタン係01のやる仕事 n } n if (xbs.getSource() == xbt02){ 24: x = x + 10; //ボタン係02のやる仕事 n } 18: repaint(); 19: } 20: } n n15: xButtonAdapter xia01 = new xButtonAdapter(); //ボタン係01生成 n22: xButtonAdapter xia02 = new xButtonAdapter(); //ボタン係02生成 ------------------------------------------------------------------------ ▼ ボタン係共通化サンプル 変更したプログラムの行番号を付け替えます。 1: import java.applet.Applet; 2: import java.awt.Graphics; 3: import java.awt.Image; 4: import java.awt.event.ActionListener; // ボタン係 5: import java.awt.Button; // ボタン(表ボタン,見た目を作る) 6: import java.awt.event.ActionEvent; // ボタンセンサ(裏ボタン,黒子) 7: 8: public class xSmpGUI02 extends Applet{ 9: 10: Image ximg; 11: int x, y; 12: 13: Button xbt01 = new Button("←"); // 表ボタン生成 14: Button xbt02 = new Button("→"); 15: 16: class xButtonAdapter implements ActionListener{ 17: public void actionPerformed(ActionEvent xbs){ 18: if (xbs.getSource() == xbt01){ 19: x = x - 10; //ボタン係01のやる仕事 20: } 21: if (xbs.getSource() == xbt02){ 22: x = x + 10; //ボタン係02のやる仕事 23: } 24: repaint(); 25: } 26: } 27: 28: xButtonAdapter xia01 = new xButtonAdapter(); //ボタン係01生成 29: xButtonAdapter xia02 = new xButtonAdapter(); //ボタン係02生成 30: 31: public void init(){ 32: ximg = getImage(getDocumentBase(),"img01.gif"); 33: x = 0; y = 0; 34: 35: add(xbt01); //表ボタンを本体プログラムの画面に貼付 36: add(xbt02); 37: 38: xbt01.addActionListener(xia01); // 表ボタンが自分のボタン係任命 39: xbt02.addActionListener(xia02); 40: } 41: 42: public void paint(Graphics xg){ 43: xg.drawImage(ximg, x, y, this); //画面を表示 44: } 45: } 共通化したプログラムを見ると,上,下移動のボタンを2つ追加した場合の 追加場所が,わかりやすくやすくなったのが納得できるでしょう。 ------------------------------------------------------------------------ ▼ 間接法を利用 無名インスタンス利用 マウス係は,今までのように,無名インスタンスを利用して,消すことができ ます。 xSmpGUI02.java を直しましょう。 変更前 28: xButtonAdapter xia01 = new xButtonAdapter(); //ボタン係01生成 29: xButtonAdapter xia02 = new xButtonAdapter(); //ボタン係02生成 30: 31: public void init(){ 32: ximg = getImage(getDocumentBase(),"img01.gif"); 33: x = 0; y = 0; 34: 35: add(xbt01); //表ボタンを本体プログラムの画面に貼付 36: add(xbt02); 37: 38: xbt01.addActionListener(xia01); // 表ボタンが自分のボタン係任命 39: xbt02.addActionListener(xia02); 40: } xia01, xia02 の名前が無くなります。 n28: n29: 30: 31: public void init(){ 32: ximg = getImage(getDocumentBase(),"img01.gif"); 33: x = 0; y = 0; 34: 35: add(xbt01); //表ボタンを本体プログラムの画面に貼付 36: add(xbt02); 37: 38: xbt01.addActionListener(new xButtonAdapter()); n // 表ボタンが自分のボタン係任命 39: xbt02.addActionListener(new xButtonAdapter()); 40: } 表ボタンのインスタンス名の xbt01, xbt02 は, 16: class xButtonAdapter implements ActionListener{ 17: public void actionPerformed(ActionEvent xbs){ 18: if (xbs.getSource() == xbt01){ 19: x = x - 10; //ボタン係01のやる仕事 20: } 21: if (xbs.getSource() == xbt02){ 22: x = x + 10; //ボタン係02のやる仕事 23: } 24: repaint(); 25: } 26: } で,名前で利用されているため,消すことができません。 無名インスタンスを利用したプログラムは以下の通りでした。 1: import java.applet.Applet; 2: import java.awt.Graphics; 3: import java.awt.Image; 4: import java.awt.event.ActionListener; // ボタン係 5: import java.awt.Button; // ボタン(表ボタン,見た目を作る) 6: import java.awt.event.ActionEvent; // ボタンセンサ(裏ボタン,黒子) 7: 8: public class xSmpGUI03 extends Applet{ 9: 10: Image ximg; 11: int x, y; 12: 13: Button xbt01 = new Button("←"); // 表ボタン生成 14: Button xbt02 = new Button("→"); 15: 16: class xButtonAdapter implements ActionListener{ 17: public void actionPerformed(ActionEvent xbs){ 18: if (xbs.getSource() == xbt01){ 19: x = x - 10; //ボタン係01のやる仕事 20: } 21: if (xbs.getSource() == xbt02){ 22: x = x + 10; //ボタン係02のやる仕事 23: } 24: repaint(); 25: } 26: } 27: 28: xButtonAdapter xia01 = new xButtonAdapter(); //ボタン係01生成 29: xButtonAdapter xia02 = new xButtonAdapter(); //ボタン係02生成 30: 31: public void init(){ 32: ximg = getImage(getDocumentBase(),"img01.gif"); 33: x = 0; y = 0; 34: 35: add(xbt01); //表ボタンを本体プログラムの画面に貼付 36: add(xbt02); 37: 38: xbt01.addActionListener(new xButtonAdapter()); 39: // 表ボタンが自分のボタン係任命 40: xbt02.addActionListener(new xButtonAdapter()); 41: } 42: 43: public void paint(Graphics xg){ 44: xg.drawImage(ximg, x, y, this); //画面を表示 45: } 46: } ------------------------------------------------------------------------ ▼ GUI GUI の代表的な部品であるボタンを今回扱いました。GUI の部品は,それぞれ, 用途によって,固有のプログラミングの仕方があります。それらは,また,別の 号で扱います。 次号は,アプレットにボタン等を貼り付けたときの配置について,勉強します。 ------------------------------------------------------------------------ ▼ 今回のサンプルのソース 例 j21-01 xSmpGUI01.java 高レベルイベント処理 ソース http://www.yscon.co.jp/j/java/jmaga/j22/xSmpGUI01.java 動作 http://www.yscon.co.jp/j/java/jmaga/j22/xSmpGUI01.htm xSmpGUI01.htm