第 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 概要
すべてがオブジェクト
「コンポーネント」という
JFrameJLabel JTextField
14.1.2 Swing を使ってみよう
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);//表示する }}
例題
14-1(Example14_1.java)
① ウインドウを出す
実行結果
次はこのウインドウにボタンを
乗せてみましょう!
② カスタムウインドウを作る
ウインドウにボタンを乗せる
JFrame
を継承して、カスタムウインドウ
を作ります
J Fr ame
But t onFr ame
Swing
プログラム
表示する
()再描画
()など
ButtonFrame のリスト
import javax.swing.*;//swing
クラスライブラリの利用を宣言する
import java.awt.*;//swingクラスライブラリの利用を宣言する
//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);
}
例題
14-2(ButtonFrame.java)
ButtonFrame を表示する Main
// ウインドウにボタンを乗せる
// カスタムフレーム ( ウインドウ ) の作成
public class Example14_2 {//
プログラム・メイン // フレームを起動する
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(Example14_2.java)
実行結果
ボタンが乗せられました。
しかし、押しても何も起こりません。
次は、ボタンが押されたとき、プログラムを
終了するようにしましょう!
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 )
ハードウエアを 常に見張っている 唯一のプログラム
プログラム
イベント・ハンドラ イベント
イベント・ディスパッチャー
押されたよ
EventObjectEventListener Swing
が提供
② イベントハンドラの作成
import java.awt.event.*;//event
クラスライブラリの利用を宣言する
// ボタンを押したときのイベントハンドラ クラス
public class ExitButtonListener implements ActionListener{
//
ボタンが押されたときのイベントハンドラ
public void actionPerformed(ActionEvent e){
System.exit(0);//
プログラムを終了する }
メソッド名はインターフェイスが }
決めているので間違えないように
ActionEvent
は
EventObjectの
サブクラスで、イベントを表すクラス
ActionListenerは
EventListenerの サブインターフェイス
例題
14-3(ExitButtonListener.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);
// イベントハンドラを設定する
ExitButtonListener listener = new ExitButtonListener();// イベントハンドラをインスタンス化 button.addActionListener(listener);// イベントハンドラを受信者として登録する
// ボタンをウインドウに乗せる
getContentPane().add(button);
} }
イベントハンドラを生成し、
addActionListener()
メソッドを使って 登録する
例題
14-3(ButtonFrame.java)
実行してみましょう!
ボタンを押すと、ウインド
ウが 閉じて終了するはずです
(Java テクニック )
④ インナークラス
//JFrameクラスを継承したカスタムフレーム(ウインドウ)クラス public class ButtonFrame extends JFrame{
//コンストラクタ
public ButtonFrame(){
//ボタンを設定する //途中割愛
// イベントハンドラを設定する
ExitButtonListener listener = new ExitButtonListener();//イベントハンドラをインスタンス化 button.addActionListener(listener);//イベントハンドラを受信者として登録する
// ボタンをウインドウに乗せる
getContentPane().add(button);
}
//ボタンを押したときのイベントハンドラ インナークラス
class ExitButtonListener implements ActionListener{
//ボタンが押されたときのイベントハンドラ
public void actionPerformed(ActionEvent e){
System.exit(0);//プログラムを終了する }
}
例題
14-4(ButtonFrame.java)
インナークラス
クラスの中にクラスを書くことができ る
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 アプリケーションのオブジェクト は再利用できるものがある
商品 - 製造年月日
商品種類 - 名前 - 商品番号 - 価格
商品保管庫 + 追加( ) 金
- 価値 勘定 CUI User App
+ 追加( ) + 削除( )
CUI AdminApp 商品種類リスト
+ 追加( ) + 削除( ) 1
0. . n 1
0. . n
再利用可能
GUI 自動販売機の構成
GUI になっても構造は変わらない
商品 - 製造年月日
商品種類 - 名前 - 商品番号 - 価格
商品保管庫 + 追加( ) + 削除( ) 金
- 価値
0. . n 1
0. . n 1
勘定 + 追加( ) + 削除( )
AdminFr ame
User Fr ame 商品種類リスト
+ 追加( ) + 削除( ) 1
0. . n 1
0. . n
② Model と View の分離
再利用できるものとできないものの違
いを考える
Model と View
再利用できるもの
自動販売機における実体や概念の構造に関 わる部分→
Model
再利用できないもの
表示に関する部分
→ View
(アプリケーションロジックに関わる部
分)
Model と View の分離
Model と View を分離しておくことに よって、表示の変更が容易になる
分離していなかったら
GUIは始めから作り 直し
商品 - 製造年月日
商品種類 - 名前 - 商品番号 - 価格
商品保管庫 + 追加( ) 金
- 価値
0. . n 1
0. . n 1
勘定 + 追加( ) + 削除( )
AdminFr ame
UserFr ame 商品種類リスト
+ 追加( ) + 削除( ) 1
0. . n 1
0. . n
Model
クラス群 実体や概念
View
クラス群
表示役
③ 現状の Model の問題点
ItemTypeList クラスの display() メソッ ドは、 CUI 専用のコードになっている
// 商品種類を表示する
public void display(){
for(int i=0;i<size;i++){
//
商品種類を表示
System.out.println(itemTypeArray[i].getId()+":"+itemTypeArray[i].getName()+":"
+itemTypeArray[i].getPrice()+"
円 ");
} }
※ ItemStock
クラスも同様
例題
11-1(ItemTypeList.java)
#display()
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()+"
円 ");
} }
size()
メソッドと
get(index)メソッド があれば、表示可能
例題
11-2(CUIAdminApp.java)
# showItemTypeList()
Model-View 分離
Model と View で責任を分離したプログ ラムの利点
表示の変更が容易に行える
様々な表示(
CUI,GUI)に対応した
Modelプログラムが書ける
重複コードがなくなる
14.3.3
GUI 自動販売機プログラミン グ
① 自動販売機用コンポーネント
② GUI 自動販売機の起動
③ UserFrame 解説
④ 100 円投入ボタンを追加する
① 自動販売機用コンポーネント (1)
BackgroundPanel
クラス
背景用のコンポーネントです。
この上に他の自販機コンポーネントを乗せる ことができます。
ItemImagePanel
クラス
商品種類を表示するための コンポーネントです。
代表的なクラス
① 自動販売機用コンポーネント (2)
BuyButton
クラス 購入ボタンです
ProductOutlet
クラス 商品取り出し口です
CoinDeposit
クラス
投入金額を表示します
② GUI 自動販売機の起動
//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);// 表示
// 購入ウインドウを生成して表示する
UserFrame userFrame = new UserFrame(itemTypeList,account);//
生成 userFrame.setVisible(true);// 表示
}
itemTypeList
と
Account
を生成して
2
つのウインドウに渡している
例題
14-6(Example14_6.java)
③ UserFrame 解説
コンストラクタ
各種コンポーネントを生成して、ウインド ウに貼り付ける
更新メソッド (3 種類 )
Model
の状態を反映して、表示を更新するた
めに使う
イベント・ハンドラ
ボタンが押された時のイベントハンドラを 記述
例題
14-6 (UserFeame.java)④ 100 円投入ボタンを追加す る
100 円投入できるようにする
ボタンが押されたら
100 円投入ボタンを追加する
//ユーザフレーム(商品購入メインウインドウ)クラス // 説明に不要な部分を割愛してある
public class UserFrame extends JFrame{
public JButton button100 = new JButton();//100円ボタン // コンストラクタ
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();//状態を更新する
} }
ボタン生成
ボタン設定
イベント・ハンドラ
例題
14-7 (UserFeame.java)イベント・ハンドラ解説
//100
円投入ボタン・イベントハンドラ
class Button100_ActionListener implements java.awt.event.ActionListener{
public void actionPerformed(ActionEvent e) { account.insert(new Money(100));//100
円投入する stateUpdate();// 状態を更新する
} }
投入金勘定への金の追加
CUI
と同様
stateUpdate()
を呼ぶ
構造が変化したら
stateUpdate()を呼ぶと表示が更新される
課題ヒント
課題 14-3: 購入ボタンのイベント・ハン ドラを実装せよ
// ユーザフレーム(商品購入メインウインドウ)クラス // 購入ボタンのイベントハンドラ以外は割愛
public class ShoppingFrame extends JFrame{
//
購入ボタン・イベントハンドラ
// 押されたボタンと、そのボタンが対象とする商品の種類が引数
public void buyButton_pressed(BuyButton buyButton,ItemType itemType){
}
}
購入ボタン用のイベントハンドラが用意されている
//
購入ボタン・イベントハンドラ
// 押されたボタンと、そのボタンが対象とする商品の種類が引数
public void buyButton_pressed(BuyButton buyButton,ItemType itemType){
//
買えるかどうか確認する // 在庫の確認をする
//
投入されている金が価格より高いか確認をする
//購入する
// 保管庫から商品を取り出す
productOutlet.addItem(item); //
取り出し口に出す
//おつりをだす
System.out.println("
おつりは~~円です "); // おつりの表示
//投入金勘定をリセットする
stateUpdate();// 状態を更新する
}購入イベント・ハンドラの実装
プログラムの目的(コメント)は、
CUIプログラムと同様にな る