第14回 GUIの構成とイベント・ ドリブン ~GUIを使ったプログラム(Ⅰ)~ 学習目標 イベント・ドリブンプログラミングの利点を説 明できる Swingを利用して簡単なGUIプログラムが 書ける 簡単なカスタムウインドウを表示できる イベントハンドラの生成・登録ができる ModelとViewを分離する設計について議 論できる GUIアプリケーション 今回はいよいよGraphical User Interface に挑戦します 購入画面 管理画面 14.1 SwingAPIを使う 14.1.1 Swing概要 14.1.2 Swingを使ってみよう 14.1.1 Swing概要 JavaでGUIのプログラムを書くためのAPI GUIを一から作るのは大変 GUIに関するクラス・ライブラリ群は「Swing」と 呼ばれている ①ウインドウを出す ②カスタムウインドウを作る Swing概要 すべてがオブジェクト JLabel 「コンポーネント」という JFrame JTextField JButton 14.1.2 Swingを使ってみよう ①ウインドウを出す 例題14-1 (Example14_1.java) import javax.swing.*;//swingクラスライブラリの利用を宣言する import java.awt.*;//swingクラスライブラリの利用を宣言する //ウインドウを表示する public class Example14_1 { //プログラム・メイン //フレームを起動する public static void main(String args[]){ JFrame frame = new JFrame();//Swingで提供されるJFrameオブジェクト生成 frame.setTitle("初めてのウインドウ");//タイトル設定 frame.setSize(200,200);//大きさ設定 frame.setLocation(50,50);//位置設定 frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);//ウインドウが閉じたときに プログラムが終了するように設定 frame.setVisible(true);//表示する } } 実行結果 次はこのウインドウにボタンを 乗せてみましょう! ②カスタムウインドウを作る ウインドウにボタンを乗せる JFrameを継承して、カスタムウインドウを作り ます Swing プログラム 表示する() 再描画()など JFrame ButtonFrame ButtonFrameのリスト import javax.swing.*;//swingクラスライブラリの利用を宣言する import java.awt.*;//swingクラスライブラリの利用を宣言する 例題14-2 (ButtonFrame.java) //JFrameクラスを継承したカスタムフレーム(ウインドウ)クラス //ボタンが一つ乗せられている public class ButtonFrame extends JFrame{ //コンストラクタ public ButtonFrame(){ getContentPane().setLayout(null);//ウインドウに載せられるすべてのオブジェクトの位置 を自分で設定できるようにする。 //ボタンを設定する JButton button = new JButton();//ボタンをインスタンス化 button.setText("初めてのボタン");//ボタンのラベル名設定 button.setSize(150,20);//ボタンの大きさ設定 button.setLocation(20,50);//ボタンの位置設定(ウインドウからの相対位置) //ボタンをウインドウに乗せる getContentPane().add(button); } } ButtonFrameを表示するMain //ウインドウにボタンを乗せる //カスタムフレーム(ウインドウ)の作成 public class Example14_2 { 例題14-2 (Example14_2.java) //プログラム・メイン //フレームを起動する public static void main(String args[]){ JFrame frame = new ButtonFrame();//カスタムフレームオブジェクト生成 frame.setTitle("初めてのウインドウ");//タイトル設定 frame.setSize(200,200);//大きさ設定 frame.setLocation(50,50);//位置設定 frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);//ウインドウが閉じたときに プログラムが終了するように設定 frame.setVisible(true);//表示する } } 実行結果 ボタンが乗せられました。 しかし、押しても何も起こりません。 次は、ボタンが押されたとき、プログラムを 終了するようにしましょう! 14.2 イベント・ドリブンプログラミング 14.2.1 ボタンが押された時の処理を考え る 14.2.2 Javaによるイベント・ドリブンプログ ラミング 14.2.1 ボタンが 押された時の処理を考える ①原始的な方法 ポーリング 一定期間ごとにハードウエアの状態を調べる ハードウエアの状態を調べる 何処にいる? プログラム 動いてないよ! 押されてる? プログラム “a”が押されてます ハードウエアを調べるプログラム 下記のメソッドを一定期間ごとに動かす //Javaではない仮想言語 public void ボタンが押されたかどうかを調べて、押されていたら終了する (){ マウスの位置を調べる(); if(マウスの位置がButtonの中にある){ マウスの状態を調べる(); if(マウスが押されている){ if(押されているのは、マウスの左ボタンである){ プログラムを終了する } } } } } ポーリングの問題点 考えてみよう ポーリングの問題点 効率が悪い(CPUに負担をかける) 動いていないかもしれないのに調べる必要が ある マウスの正確な動きを捉えるには、相当細か い期間ごとに調べなければならない プログラミングが大変 ややこしいメソッドを用意する必要がある ボタンがたくさんあったら大変 ②イベント・ドリブン プログラミング イベント・ドリブン ポーリングの問題点を解決するためのプログ ラミングスタイル 処理をイベント毎に分割して記述して、 必要 に応じて呼びだされ, 処理される イベント・ドリブンの考え方 押されたよ! ハードウエアを 常に見張っている 唯一のプログラム 常に見張っている プログラム 押されたよ! プログラム イベント・ドリブンの用語 イベント・ディスパッチャー イベント ハードウエアを 常に見張っている 唯一のプログラム 押されたよ! イベント・ハンドラ プログラム イベント・ドリブンプログラミング イベントドリブン型プログラムを作る時は、 ただひたすら、イベントハンドラをどう書く かに集中すれば良い public void ボタンが押されたときの処理(){ System.exit(0); } これだけのメソッドを書けばよくなる 14.2.2 Javaによる イベント・ドリブンプログラミング ①Javaによるイベント・ドリブン ②イベントハンドラの作成 ③イベントハンドラの登録 Javaテクニック ④インナークラス ⑤テキストフィールドと連動するプログラム ①Javaによるイベント・ドリブン JavaのSwingフレームワークはこの機能を 標準で持っている Javaではイベントハンドラのことを EventListenerと呼び、オブジェクトとして表 現 Javaではイベントもオブジェクトとして扱う (EventObject) Javaによるイベント・ドリブン(2) イベント・ディスパッチャー Swingが提供 ハードウエアを 常に見張っている 唯一のプログラム イベント イベント・ハンドラ EventObject 押されたよ EventListener プログラム ②イベントハンドラの作成 例題14-3 (ExitButtonListener.java) import java.awt.event.*;//eventクラスライブラリの利用を宣言する //ボタンを押したときのイベントハンドラ クラス public class ExitButtonListener implements ActionListener{ //ボタンが押されたときのイベントハンドラ public void actionPerformed(ActionEvent e){ ActionListenerはEventListenerの サブインターフェイス System.exit(0);//プログラムを終了する } } メソッド名はインターフェイスが 決めているので間違えないように ActionEventはEventObjectの サブクラスで、イベントを表すクラス ③イベントハンドラの登録 //JFrameクラスを継承したカスタムフレーム(ウインドウ)クラス public class ButtonFrame extends JFrame{ //コンストラクタ public ButtonFrame(){ getContentPane().setLayout(null); //ボタンを設定する JButton button = new JButton(); button.setText("初めてのボタン"); button.setSize(150,20); button.setLocation(20,50); 例題14-3 (ButtonFrame.java) イベントハンドラを生成し、 addActionListener()メソッドを使って 登録する //イベントハンドラを設定する ExitButtonListener listener = new ExitButtonListener();//イベントハンドラをインスタンス化 button.addActionListener(listener);//イベントハンドラを受信者として登録する //ボタンをウインドウに乗せる getContentPane().add(button); } } 実行してみましょう! ボタンを押すと、ウインドウが 閉じて終了するはずです (Javaテクニック) ④インナークラス //JFrameクラスを継承したカスタムフレーム(ウインドウ)クラス public class ButtonFrame extends JFrame{ //コンストラクタ public ButtonFrame(){ 例題14-4 (ButtonFrame.java) //ボタンを設定する //途中割愛 //イベントハンドラを設定する ExitButtonListener listener = new ExitButtonListener();//イベントハンドラをインスタンス化 button.addActionListener(listener);//イベントハンドラを受信者として登録する //ボタンをウインドウに乗せる getContentPane().add(button); } //ボタンを押したときのイベントハンドラ インナークラス class ExitButtonListener implements ActionListener{ //ボタンが押されたときのイベントハンドラ public void actionPerformed(ActionEvent e){ System.exit(0);//プログラムを終了する } } } インナークラス クラスの中にクラスを書くことができる Javaの便利な仕組み インナークラスを使う利点は何でしょうか? ⑤テキストフィールド と連動するプログラム ボタンが押された時、テキストフィールドの 内容を変更するプログラム ボタンが押された テキストフィールド と連動するプログラムのリスト //JFrameクラスを継承したカスタムフレーム(ウインドウ)クラス public class ButtonFrame extends JFrame{ private JTextField textField = new JTextField();//テキストフィールド テキストフィールドを 生成する //コンストラクタ public ButtonFrame(){ //ボタンを設定する(割愛) //イベントハンドラを設定する(割愛) //ボタンをウインドウに乗せる(割愛) //テキストフィールドを設定する textField.setText("ボタンは押されていません"); textField.setBounds(20,100,150,20);//位置、大きさ設定(x,y,width,height) getContentPane().add(textField);//テキストフィールドをウインドウに載せる } //ボタンを押したときのイベントハンドラ インナークラス public class TextFieldChangeButtonListener implements ActionListener{ //ボタンが押されたときのイベントハンドラ public void actionPerformed(ActionEvent e){ textField.setText("ボタンが押されました"); } } } テキストフィールドの 内容を変更する インナークラスの利点 簡単に他のコンポーネントと連動できるよ うになる もちろん、イベントハンドラに参照を渡すように して、プログラムを分割してもできる プログラムを分割する必要がある場合はそうする 14.3 GUI自動販売機の構成 14.3.1 GUI自動販売機概要 14.3.2 ModelとViewの分離 14.3.3 GUI自動販売機プログラミング 14.3.1 GUI自動販売機概要 自動販売機用コンポーネントを利用する 基本構造 管理者用ウインドウ(AdminFrameクラス) CUI版CUIAdminAppの機能を備えている ユーザ用ウインドウ(UserFrameクラス) CUI版CUIUserAppの機能を備えている 基本構造 ユーザウインドウ 管理者ウインドウ 14.3.2 ModelとViewの分離 ①CUI自動販売機の再利用 ②ModelとViewの分離 ③現状のModelの問題点 ④display()メソッドの廃止 ①CUI自動販売機の再利用 CUIアプリケーションのオブジェクトは再利 用できるものがある 勘定 金 - 価値 CUIUserApp + 追加() + 削除() 商品種類 - 名前 - 商品番号 0..n - 価格 商品種類リスト + 追加() 1 + 削除() 商品保管庫 商品 - 製造年月日 0..n CUIAdminApp + 追加() 1 + 削除() 再利用可能 GUI自動販売機の構成 GUIになっても構造は変わらない 勘定 金 - 価値 商品種類 - 名前 - 商品番号 - 価格 AdminFrame + 追加() + 削除() 商品種類リスト 0..n + 追加() 1 + 削除() 商品保管庫 商品 - 製造年月日 0..n + 追加() 1 + 削除() UserFrame ②ModelとViewの分離 再利用できるものとできないものの違いを 考える ModelとView 再利用できるもの 自動販売機における実体や概念の構造に関 わる部分→Model 再利用できないもの 表示に関する部分 →View (アプリケーションロジックに関わる部分) ModelとViewの分離 ModelとViewを分離しておくことによって、 表示の変更が容易になる 分離していなかったらGUIは始めから作り直し 実体や概念 Viewクラス群 UserFrame 表示役 + 追加() + 削除() Modelクラス群 商品種類 - 名前 - 商品番号 - 価格 AdminFrame 勘定 金 - 価値 商品種類リスト 0..n + 追加() 1 + 削除() 商品保管庫 商品 - 製造年月日 0..n + 追加() 1 + 削除() ③現状のModelの問題点 ItemTypeListクラスのdisplay()メソッドは、 CUI専用のコードになっている 例題11-1 (ItemTypeList.java) #display() //商品種類を表示する public void display(){ for(int i=0;i<size;i++){ //商品種類を表示 System.out.println(itemTypeArray[i].getId()+":"+itemTypeArray[i].getName()+":" +itemTypeArray[i].getPrice()+"円"); } } ※ItemStockクラスも同様 display()メソッド CUIとGUIでは異なる表示にしたい 現状のdisplay()メソッドではGUIに対応できな い Modelは構造だけに責任をもつ 1001:cola:120円 1002:soda:120円 CUI商品種類表示 GUI商品種類表示 ④display()メソッドの廃止 表示の責任はViewが持つべきだから、 display()メソッドは廃止する 変わりにCUI、GUIがそれぞれの表示をで きるようにメソッドを追加する int size() 要素数を取得する ItemType get(int index) index番目の商品種類を取得する display()はViewに任せる //商品種類リストを閲覧する public void showItemTypeList(){ itemTypeList.display(); } //商品種類リストを閲覧する public void showItemTypeList(){ int len = itemTypeList.size(); for(int i=0;i<len;i++){ ItemType itemType = itemTypeList.get(i); System.out.println(itemType.getId()+":" +itemType.getName()+":" +itemType.getPrice()+"円"); } } 例題11-2 (CUIAdminApp.java) # showItemTypeList() size()メソッドと get(index)メソッド があれば、表示可能 Model-View分離 ModelとViewで責任を分離したプログラム の利点 表示の変更が容易に行える 様々な表示(CUI,GUI)に対応したModelプロ グラムが書ける 重複コードがなくなる 14.3.3 GUI自動販売機プログラミング ①自動販売機用コンポーネント ②GUI自動販売機の起動 ③UserFrame解説 ④100円投入ボタンを追加する ① 自動販売機用コンポーネント(1) 代表的なクラス BackgroundPanelクラス 背景用のコンポーネントです。 この上に他の自販機コンポーネントを乗せる ことができます。 ItemImagePanelクラス 商品種類を表示するための コンポーネントです。 ① 自動販売機用コンポーネント(2) BuyButtonクラス 購入ボタンです ProductOutletクラス 商品取り出し口です CoinDepositクラス 投入金額を表示します ②GUI自動販売機の起動 例題14-6 (Example14_6.java) //GUI自動販売機を起動するためのメイン・クラス public class Example14_6 { /** * プログラム・メイン * 操作するための2つのウインドウ(管理ウインドウ,購入ウインドウ) * を生成、表示する */ public static void main(String args[]){ ItemTypeList itemTypeList = new ItemTypeList(); //商品種類リストを生成 Account account = new Account(); //投入金勘定を生成 //管理ウインドウを生成して表示する AdminFrame adminFrame = new AdminFrame(itemTypeList,account);//生成 adminFrame.setVisible(true);//表示 itemTypeListと Accountを生成して 2つのウインドウに渡している //購入ウインドウを生成して表示する UserFrame userFrame = new UserFrame(itemTypeList,account);//生成 userFrame.setVisible(true);//表示 } ③UserFrame解説 コンストラクタ 各種コンポーネントを生成して、ウインドウに 貼り付ける 更新メソッド(3種類) 例題14-6 (UserFeame.java) Modelの状態を反映して、表示を更新するた めに使う イベント・ハンドラ ボタンが押された時のイベントハンドラを記述 ④100円投入ボタンを追加する 100円投入できるようにする ボタンが押されたら 100円投入ボタンを追加する //ユーザフレーム(商品購入メインウインドウ)クラス //説明に不要な部分を割愛してある public class UserFrame extends JFrame{ public JButton button100 = new JButton();//100円ボタン 例題14-7 (UserFeame.java) ボタン生成 //コンストラクタ public UserFrame(ItemTypeList newItemTypeList,Account newAccount){ //100円投入ボタン設定 button100.setText("100円"); button100.setBounds(new Rectangle(385, 240, 79, 27)); button100.addActionListener(new Button100_ActionListener()); background.add(button100, null); ボタン設定 } //100円投入ボタン・イベントハンドラ class Button100_ActionListener implements java.awt.event.ActionListener{ public void actionPerformed(ActionEvent e) { account.insert(new Money(100));//100円投入する stateUpdate();//状態を更新する } } } イベント・ハンドラ イベント・ハンドラ解説 投入金勘定への金の追加 CUIと同様 stateUpdate()を呼ぶ 構造が変化したらstateUpdate()を呼ぶと表示が更新 される //100円投入ボタン・イベントハンドラ class Button100_ActionListener implements java.awt.event.ActionListener{ public void actionPerformed(ActionEvent e) { account.insert(new Money(100));//100円投入する stateUpdate();//状態を更新する } } 課題ヒント 課題14-3:購入ボタンのイベント・ハンドラ を実装せよ //ユーザフレーム(商品購入メインウインドウ)クラス //購入ボタンのイベントハンドラ以外は割愛 public class ShoppingFrame extends JFrame{ //購入ボタン・イベントハンドラ //押されたボタンと、そのボタンが対象とする商品の種類が引数 public void buyButton_pressed(BuyButton buyButton,ItemType itemType){ } } 購入ボタン用のイベントハンドラが用意されている 購入イベント・ハンドラの実装 プログラムの目的(コメント)は、CUIプログラムと同様になる コメントに合わせてプログラムを書く //購入ボタン・イベントハンドラ //押されたボタンと、そのボタンが対象とする商品の種類が引数 public void buyButton_pressed(BuyButton buyButton,ItemType itemType){ //買えるかどうか確認する //在庫の確認をする //投入されている金が価格より高いか確認をする //購入する //保管庫から商品を取り出す productOutlet.addItem(item); //取り出し口に出す 取り出し口に出すプログラム itemは取り出した商品 //おつりをだす System.out.println("おつりは~~円です"); //おつりの表示 //投入金勘定をリセットする stateUpdate();//状態を更新する } 構造が変化したら、状態を更新する
© Copyright 2024 ExpyDoc