第14回 GUIの構成とイベント・ドリブン
Download
Report
Transcript 第14回 GUIの構成とイベント・ドリブン
第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();//状態を更新する
}
構造が変化したら、状態を更新する