<?xml version='1.0' encoding='Shift_JIS' ?>
<doc xml:lang='ja'>
	<head>
	</head>
	<body>
		<p>この章では、サンプルを示しながらプレゼンテーションコンポーネントを作成する方法を記述します。なお、実際にソースコードを紹介するのでJava言語に関する知識がある程度必要ですので、ご了承ください。</p>


		<subsection title="継承したクラスを作成する">
			<p>最初にクラスを作成します。作成するプレゼンテーションコンポーネントの種類に応じて以下の２つのクラスのどちらかを継承して作成します。</p>
				<dl> 
					<dt>ウィンドウ型</dt>
						<dd>org.boxed_economy.besp.presentation.gui.AbstractInternalFrameComponent</dd>
					<dt>グラフ用</dt>
						<dd>org.boxed_economy.components.datacollect.AbstractDataCollectComponent</dd>
				</dl>
		　　　　 
			<p>ここではサンプルとして「モデルの現在時刻を表示するプレゼンテーションコンポーネント」を作成することにします。</p>
			<p>このプレゼンテーションコンポーネントはグラフを表示しないので、通常のコンポーネントとし、AbstractInternalFrameComponentを継承してClockWindowという名前で作成します。</p>
			<p>ちなみに、このプレゼンテーションコンポーネントは「モデル・チュートリアル」で触れたmarketforlemonモデルで動作することを最低条件として作成します。どのようなモデルで動くようなプレゼンテーションコンポーネントを作成することもできますが、多くは（開発における手間などを考慮して）特定のモデルで動作することに特化したプレゼンテーションコンポーネントを作成することになるでしょう。</p>
			<p>さて、ソースコードはこのようになります。２つほど空のメソッドがありますが、これについては後述します。</p>
				<program title="ClockWindow1" src="marketforlemonsrc/presentation/ClockWindow1.java" normalizer="javasrc" javasrcSyntaxHilight="true" encoding="Shift_JIS" />
		</subsection>
			
		<subsection title="イベントリスナの実装">
			<p>それぞれのプレゼンテーションコンポーネントが受け取りたいイベントを決め、Listenerインターフェースを実装します。この部分がプレゼンテーションコンポーネントの作成においてカギとなる部分です。以下の表からイベントを選びます。そのイベントのListenerインターフェースを実装します。</p>
			<p>これらのイベントは大きく分けて３種類あります。１つはシミュレーションそのもの状態を監視するイベント群で、もう１つはモデルの内容、状態を監視するイベント群です。通常はこのイベント群を利用します。最後はデフォルトのイベント群です。それぞれ分けて表として紹介します。</p>
		
			<table style="width:100%" title="BESPにおけるイベント(シミュレーションそのものの状態を監視するイベント群)" >
				<thead>イベント名,メソッド,送られるタイミング,リスナ追加・削除の方法</thead>
					<tbody>ModelContainerEvent,prepareWorldOpen,モデルが読み込まれる直前,自動的に
		ModelContainerEvent,worldOpend,モデルが読み込まれた直後,自動的に
		ModelContainerEvent,prepareWorldClose,モデルが破棄される直前,自動的に
		ModelContainerEvent,worldClosed,モデルが破棄された直後,自動的に
		PresentationContainerEvent,presentationComponentAdded,プレゼンテーションコンポーネント追加時,自動的に
		PresentationContainerEvent,presentationComponentRemoved,プレゼンテーションコンポーネント削除時,自動的に
		SimulationStateEvent,simulationStarted,シミュレーション開始直後,自動的に
		SimulationStateEvent,simulationStopping,シミュレーション停止処理中,自動的に
		SimulationStateEvent,simulationStopped,シミュレーション停止後,自動的に</tbody> 
			</table>
			<p>これらのイベントは自動的にリスナーの登録・削除を行います。</p>
			<table style="width:100%" title="BESPにおけるイベント(モデルの内容・状態を監視するイベント群)"> 
				<thead>イベント名,メソッド,送られるタイミング,リスナ追加・削除の方法</thead>
					<tbody>TradeEvent,tradeCompleted,経路閉鎖時に,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateAgentEvent,goodsAdded,エージェントに財が追加されたとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateAgentEvent,goodsRemoved,エージェントから財が削除されたとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateAgentEvent,informationAdded,エージェントに情報が追加されたとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateAgentEvent,informationRemoved,エージェントにから情報が削除されたとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateAgentEvent,relationAdded,エージェントに関係が追加されたとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateAgentEvent,relationRemoved,エージェントにから関係が削除されたとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateBehaviorEvent,behaviorUpdated,行動に何らかの変更があったとき(※),プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateChanelEvent,goodsSent,経路から財が送られたとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateChanelEvent,goodsReceived,経路の財が受け取られたとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateClockEvent,clockGained,時計が進んだとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateInformationEvent,informationUpdated,情報に何らかの変更があったとき(※),プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateRelationEvent,channelOpened,関係が経路を開設したとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateRelationEvent,channelClosed,関係が経路を閉鎖したとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateWorldEvent,goodsCreated,世界が財を生産したとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateWorldEvent,goodsConsumed,世界のメソッドによって財を消費したとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateWorldEvent,agentCreated,世界にエージェントが配置されたとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ
		UpdateWorldEvent,agentDestroyed,世界からエージェントが削除されたとき,プレゼンテーションコンポーネントで追加・削除メソッドを呼ぶ</tbody>
			</table>
			<p>（※）のイベントはどのようなタイミングでイベントを送るかはそれぞれ行動・情報の作成者に依存します。</p>
			<table style="width:100%" title="BESPにおけるイベント(デフォルトのイベント群)	"> 
				<thead>イベント名,メソッド,送られるタイミング,リスナ追加・削除の方法</thead>
					<tbody>（デフォルト）,initialize,プレゼンテーションコンポーネントが配置された直後,自動的に
		（デフォルト）,terminate,プレゼンテーションコンポーネントが削除される直前,自動的に</tbody> </table>
			<p>これらのデフォルトはJava言語的に厳密にはイベントというよりメッセージです。しかし、ここではあえてイベントの１種として解説します。</p> 
			<p>さて、ClockWindowですが、時刻を表示するので当然のようにUpdateClockEventを受け取ることができるように、UpdateClockListenerを実装します。そしてもうひとつ実装すべきリスナーインターフェースが存在します。ModelContainerListenerです。なぜならば、モデルそのものが変更されたとき、あるいはモデルが読み込まれた時、UpdateClockイベントを受け取るための処理を再度行わなければいけないからです。すると、ソースコードは以下のようになりました。</p>
			<program title="ClockWindow2" src="marketforlemonsrc/presentation/ClockWindow2.java" normalizer="javasrc" javasrcSyntaxHilight="true" encoding="Shift_JIS" />
			<p>全部で５つのメソッドが追加されました。</p>
		</subsection> 
			
		<subsection title="追加・削除処理の記述"> 
		<p>このようにリスナーインターフェースを追加することでメソッドが追加されましたが、メソッドの中身に処理を記述する前に先に書いておきたい処理があります。リスナーの追加・削除の具体的処理です。</p>
		<p>モデルの内容・状態を監視するイベント群は手動でこのリスナーの追加・削除を行わないといけません。</p>
		<p>追加・削除処理についてはプレゼンテーションコンポーネントにメソッドが用意されているのでそれを呼べば追加・削除処理を行うことが出来ます（それぞれのUpdateEventに対し、add・・・Listener()、remove・・・Listener()が用意されています）。</p>
		<p>この記述はどこに書いてもいいのですが、サンプルではModelContainerイベントのworldOpened()、worldClosed()それぞれに記述します。</p>
		
			<program title="ClockWindow3" src="marketforlemonsrc/presentation/ClockWindow3.java" normalizer="javasrc" javasrcSyntaxHilight="true" encoding="Shift_JIS" />
		
			<p>worldOpened()、worldClosed()に処理が追加されています。</p> 
		</subsection> 
		
		<subsection title="各メソッドの実装"> 
			<p>ここまでできれば、あとはメソッドの中身を実装するだけです。先述したように、イベントによって特定のタイミングでよばれるメソッドを実装するだけです。</p>
			<p>その前にプレゼンテーションコンポーネント実装をする時にはいくつか便利なメソッドがあらかじめ用意されています。それらを紹介します。</p>
			
			<table style="width:100%" title="プレゼンテーションコンポーネントが利用できる便利なメソッド"> 
				<thead>メソッド名,処理内容</thead>
					<tbody>
						getMainFrame,このプレゼンテーションコンポーネントが配置されているメインウィンドウを返します。
						getPresentationContainer,このプレゼンテーションコンポーネントが配置されているプレゼンテーションコンテナを返します。
						getWorld,現在読み込まれているモデルのWorldオブジェクトを返します</tbody>
			</table>
				
			<p>さて、ClockWindowもあとは中身を実装して終わりです。具体的に実装を行う部分は３つあります。GUIの初期化を行う部分と、時計を描画する部分です。時計に関しては時刻だけを表示するという実装になります。</p>
			<p>全体のソースコードは以下のようになります。</p>
				<program title="ClockWindow" src="marketforlemonsrc/presentation/ClockWindow.java" normalizer="javasrc" javasrcSyntaxHilight="true" encoding="Shift_JIS" />
			<p>コンストラクタでGUIの初期化を行っています。そして、clockGained()で時刻を取得して表示するだけです。これでClockWindowは完成です。このように表示されます。</p>
				<figure id="fig:lastyear1" src="image/cw2" title="完成したClockWindow" /> 
		</subsection>
		
		<subsection title="パッケージ配置について">
			<p>このように作成したプレゼンテーションコンポーネントですが、実際はメインウィンドウにメニューとして追加しないと、メニューを選択して表示させることはできません。ClockWindowだけメニューに追加するようにしてもいいのですが、ここは後に紹介するサンプルソースコードも合わせて一つのパッケージとしてまとめます。</p>
			<p>プレゼンテーションコンポーネントは多くの場合１つのモデルに対応しています（もちろん独立して作成しても構いません）。一つのモデルのパッケージにモデル本体とプレゼンテーションをまとめておくと管理しやすいはずです。ここでは、marketforlemonパッケージの中にmodelとpresentationの２つのパッケージを作成し、ClockWindowはそこに置くことにします。</p>
			<p>１つのプレゼンテーションパッケージには１つのプラグインクラスを置きます。このプラグインクラスはBESPPluginインターフェースを実装して作成し、public static void initializePlugin(BESPContainer container)メソッドとpublic static Class[] getDependentClasses()を実装します。前者はメニューへの追加処理、及びプレゼンテーションパッケージ全体の初期化処理などを記述し、後者は依存するパッケージを返します。</p>
			<p>メニューへの追加方法ですが、以下のように記述します（この内容についての詳細はBESPアーキテクチャ説明書で行います）。</p> 
		
			<program>CreateComponentAction cAction = new CreateComponentAction("[メニューに表示する名前]", [表示するプレゼンテーションコンポーネントのクラス名] .class);
container.getPresentationContainer().addMenuElementToShowMenu(cAction);</program>
		
			<p>MarketForLemonPluginクラスを以下のように作成します。３つほどメニューに追加するプレゼンテーションコンポーネントを記述し、依存するモデルクラスも記述しました。まだ、グラフ表示のためのDataCollectorを追加していますが、これは後述します。</p>
		
			<program title="MarketForLemonPlugin" src="marketforlemonsrc/presentation/MarketForLemonPlugin.java" normalizer="javasrc" javasrcSyntaxHilight="true" encoding="Shift_JIS" /> 
			
		</subsection>
	</body>
</doc>
