前回やったように,ボタンのような GUI部品に対するユーザ入力は,GUI部品 に関連づけられた Event Listenerによっておこなわれるが,ボタンなどの部 品に関しては,MouseEventのような低レベルのイベントではなく, ActionEventというイベントで処理する.
ボタンのような GUI部品では,mousePressを受け取ってActionEventに変換す るだけだが,テキストフィールドのようなものでは,キー入力やマウスを使っ た編集作業は内部で処理して,リターンキーが押された時に始めて, ActionEventを発生するようになっている.
また,チェックボックスのように,イベントを発生させるよりは,状態を内 部で保持しておいて,他のGUI部品を利用したイベント発生時に内部をチェッ クする使い方が主だというGUI部品もある.ただし,チェックボックスの内部 状態が変化した時に,ItemEventイベントを発生するので,それを受け取る Event Listenerを作っておけば,イベントを捕まえることができる.
import java.awt.*; import java.awt.event.*; public class GUITest2 extends Frame implements ActionListener,MouseListener{ // 画面に表示するメッセージの変数.空文字列 "" で初期化する必要がある. String message=""; Button button1, button2, button3; Checkbox check1, check2; TextField textField; GUITest2(){ setLayout(new FlowLayout()); // 「Check1」というラベルを持つチェックボックスを作り,window中に配置 add(check1=new Checkbox("Check1")); // 「Button1」というラベルを持つボタンを作り,window中に配置 add(button1=new Button("Button1")); button1.addActionListener(this); // ラベルを持たないチェックボックスを作り,window中に配置 add(check2=new Checkbox()); // ラベルを持たないボタンを作り,window中に配置 add(button2=new Button("Button2")); button2.addActionListener(this); // 幅10文字分のTextField(テキスト入力用領域)を作り,window中に配置 add(textField=new TextField(10)); textField.addActionListener(this); add(button3=new Button("Quit")); button3.addActionListener(this); // windowのサイズを 500 x 500 に変更 setSize(500,500); // windowを表示する. setVisible(true); addMouseListener(this); } public static void main(String args[]){ // GUITest2クラスのインスタンスを生成 GUITest2 window=new GUITest2(); // window内部に GUI部品を置くときのレイアウトをFlowLayoutに指定 } public void paint(Graphics g){ // 以後の描画,塗り潰しの色を黄色に指定 g.setColor(Color.yellow); // (0,0)から幅500,高さ500で描画 g.fillRect(0,0,500,500); // 以後の描画,塗り潰しの色を黒に指定 g.setColor(Color.black); // 文字列 message の内容を(50,100)の座標から描画 g.drawString(message,50,100); } // 内部の GUI 部品以外のところでマウスが押された時に呼ばれる. public void mousePressed(MouseEvent e){ int mx=e.getX(), my=e.getY(); // マウスが押された時に渡される Event と押された時のX座標,Y座標を表示 System.out.println("mouseDown("+e+","+mx+","+my+")"); // イベントの処理をおこなったことを表すため true を返す } public void mouseReleased(MouseEvent e){} public void mouseClicked(MouseEvent e){} public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} // GUI部品がイベントを処理して,その部品を含むクラスに処理結果を渡す // 際に呼ばれる. public void actionPerformed(ActionEvent e){ // イベントのターゲットは GUI 部品のオブジェクトだが, // これが Button クラスのインスタンスかどうかのチェック System.out.println(e); Object source=e.getSource(); if(source instanceof Button){ String label=e.getActionCommand(); // 押されたボタンのラベルが"Button1"かどうかのチェック if(label.equals("Quit")){ System.exit(0); } else if(label.equals("Button1")){ // その時は表示する messageは "Button1" message="Button1," + "Check1 is "+check1.getState(); } else{ // それ以外の時は表示する messageは "Unknown Button"とする. message="Button2," + "Check2 is "+check2.getState(); } } // イベントのターゲットが Checkbox クラスのインスタンスかどうかのチェック else if(source instanceof Checkbox){ // その時は チェックボックスの内容を表示 message="Checkbox"+(Checkbox)source; } // イベントのターゲットが TextField クラスのインスタンスかどうかのチェック else if(source instanceof TextField){ // その時は 内容を表示 message="TextField"+(TextField)source; } // 明示的に,書き直しをする repaint(); } }実行してみると分かるが,内部のGUI部品の内側でマウスのボタンを押した時 は,外側のFrameのmouseDownは呼ばれない.
g.fillOval(ball_x,ball_y,ball_size,ball_size);のように円で描いているが,これをイメージファイルを読み込んで,それを表 示するように変更しなさい.ボールのイメージはgimp 等で作っても良いし, どこかから持ってきても良い.
サンプルプログラムではゲームを遊んでいるわけではないことを示すために,
g.drawString("Not a game, but a excercise in CP1(Wed/tanaka)",0,200);という文字列を表示するようにしてあります.この表示は取り除かないで下さ い.
import java.awt.*; import java.awt.event.*; class BallGame extends Frame implements KeyListener{ // ボールの座標,速度のx, y成分の宣言 int ball_x=100,ball_y=100,ball_vx=16,ball_vy=12; // ボールの大きさ int ball_size=20; // 画面の幅,高さ int width=300, height=600; // バーの座標 int bar_x=0, bar_y=550; // バーの速度 int bar_vx=0; // バーの幅,高さ int bar_width=60,bar_height=10; // BallGameクラスのコンストラクタ public BallGame(){ // 親クラスである Frameのコンストラクタを呼ぶ super(); // ウィンドウのサイズを変更 setSize(width,height); // ウィンドウを表示 setVisible(true); addKeyListener(this); } public static void main(String[] args){ // BallGameクラスのインスタンスを作成 BallGame frame=new BallGame(); // スレッドを獲得 Thread t=Thread.currentThread(); for(;;){ // 0.1秒(100ミリ秒)待つ try { t.sleep(100); } catch(Exception e){} // BallGameクラスのインスタンス frame のtimeTickメソッドの呼び出し frame.timeTick(); } } void timeTick(){ // バーの移動 bar_x=bar_x+bar_vx; // 左端から飛び出そうになったら左端に合わせる if(bar_x<0) bar_x=0; // 右端から飛び出そうになったら右端に合わせる else if(bar_x+bar_width >width) bar_x=width-bar_width; // ボールの移動.古い座標を保存 int old_x=ball_x; int old_y=ball_y; // 速度に従って,次の座標を決定 ball_x=ball_x+ball_vx; ball_y=ball_y+ball_vy; // 左端から飛び出そうになったら,反射させる if(ball_x<0){ ball_x= -ball_x; ball_vx= -ball_vx; } // 右端から飛び出そうになったら,反射させる else if(ball_x >width-ball_size){ ball_x=(width-ball_size)-(ball_x-(width-ball_size)); ball_vx= -ball_vx; } // 上端から飛び出そうになったら,反射させる if(ball_y<0.0){ ball_y= -ball_y; ball_vy= -ball_vy; } // バーのある線を通過しそうになったら, else if(ball_y >bar_y && old_y<=bar_y){ // バーのある線を横切るX座標を計算 int x=old_x+(ball_x-old_x)*(bar_y-old_y)/(ball_y-old_y); // バーと接触している場合は反射させる. if(bar_x <= x && x<=bar_x+bar_width){ ball_y=bar_y-(ball_y-bar_y); ball_vy= -ball_vy; } } // 下端から飛び出そうになったら,反射させる else if(ball_y > height){ ball_vy=-ball_vy; } // 再表示 repaint(); } public void paint(Graphics g){ // 描画色を黒にする. g.setColor(Color.black); // 全体を塗り潰す g.fillRect(0,0,width,height); // 描画色を白にする. g.setColor(Color.white); // 警告文字列を(0,200)の点を左下にして描く g.drawString("Not a game, but a excercise in CP1(Wed/tanaka)",0,200); // 描画色を赤にする. g.setColor(Color.red); // ボールを描く g.fillOval(ball_x,ball_y,ball_size,ball_size); // オフスクリーンイメージへの描画色を青にする. g.setColor(Color.blue); // バーを描く g.fillRect(bar_x,bar_y,bar_width,bar_height); } // キーが押された時にこのメソッドが呼ばれる. public void keyReleased(KeyEvent e){} public void keyTyped(KeyEvent e){} public void keyPressed(KeyEvent e){ int key=e.getKeyChar(); // 'h' のキーが押された時は,バーの移動速度を -10に if(key=='h'){ bar_vx= -10; } // 'l' のキーが押された時は,バーの移動速度を 10に else if(key=='l'){ bar_vx=10; } // 'j' のキーが押された時は,バーの移動速度を 0に else if(key=='j'){ bar_vx=0; } else if(key=='q'){ System.exit(0); } } }