プロトタイプをアプリケーション・オブジェクトへリンクする > 手順 3:ユーザー・フィードバックを処理するグループ・メディエーターの作成
 
手順 3:ユーザー・フィードバックを処理するグループ・メディエーターの作成
ディスプレイを駆動するだけでなく、内部パラメーターに影響するユーザー入力を処理するアプリケーションを作成する場合は、以下の手順に従います。Rogue Waveィ Views Studio の myproto プロトタイプはわずかに拡張されて、スライダーに似たオブジェクトが追加されています。ユーザーはこのスライダーを使って温度計のアニメーション速度を変更し、温度に応じて上下するレベルの動きを速くしたり遅くしたりできます。
また、Rogue Wave Views Studio の myLib.ipl ライブラリーを開いて、この効果を達成するために追加されたアトリビュートと振る舞いを確認できます。
アプリケーション・オブジェクトとプロトタイプのインスタンスのリンクには、IlvGroupMediator クラスによって実装された Mediator デザイン・パターンを使用します。 このクラスを使用するには次のファイルのインクルードが必要です。
#include <ilviews/protos/grouplin.h>
トークン・アプリケーション・オブジェクトの定義
このチュートリアルでは、BGO とともに実装されたユーザー・インターフェースを介して表示し、制御する単純なオブジェクトの温度計を仮定します。
#if defined(ILVSTD)
#include <cmath> // for sin() function
ILVSTDUSE
#else
#include <math.h>
#endif
struct Thermometer {
IlFloat temperature;
IlUInt acceleration;
IlUInt curval;
IlvTimer timer;
// The display argument is here to allow the use of a Views timer.
Thermometer(IlvDisplay*);
~Thermometer() {}
void adjust_temp();
static void TimerProc(IlvTimer*, IlAny);
};
 
Thermometer::Thermometer(IlvDisplay* dpy)
:temperature(20), acceleration(4), curval(0),
timer(dpy, 0, 200, TimerProc, this) // see Note that follows
{
timer.run();
}
 
void Thermometer::adjust_temp()
{
temperature = 50.0 + (40.0 *
sin(degreesToRadians((IlDouble)curval)));
curval = (curval + acceleration) % 360;
}
void Thermometer::TimerProc(IlvTimer*, IlAny arg)
{
((Thermometer*)arg)->adjust_temp();
}
メモ: 一部のシステムでは、上の構文にある「this」の使用に関して警告メッセージが表示されることがあります。ただし、構文は安全なので警告は無視して構いません。
adjust_temp メソッドは定期的に呼び出されてトグル・アニメーション・タイマーを実装します。このクラスは、ユーザー・インターフェースの特定機能を一切提供しません。つまり、他のアプリケーション・オブジェクト (たとえばプラント・シミュレータなど) とともに動作できるスタンドアロンのソフトウェア・ピースとして機能することを意味しますが、その値の対話的な表示または編集を許可する機能は皆無です。本チュートリアルでは、このオブジェクトのユーザー・インターフェースを定義変更せずに作成します。
メイン・プログラムでディスプレイの作成後に、このアプリケーション・オブジェクトのインスタンスを作成します。
// create and initialize an application object.
Thermometer myThermometer(display);
アプリケーションのクラスの GroupMediator を定義する
Thermometer のインスタンスのユーザー・インターフェースを作成するため、この Thermometer クラスを処理する GroupMediator のサブクラスを定義します。
struct TemperatureWatcher:public IlvGroupMediator
{
TemperatureWatcher(IlvGroup* g, Thermometer* a)
: IlvGroupMediator(g, a) {
if(!tempSymbol) tempSymbol=IlvGetSymbol("temperature");
if(!accSymbol) accSymbol=IlvGetSymbol("acceleration");
}
IlBoolean changeValues(const IlvValue*, IlvUShort);
void queryValues(IlvValue*, IlvUShort) const;
inline Thermometer* getThermometer() const {
return (Thermometer*) getObject(); }
static IlvSymbol* tempSymbol;
static IlvSymbol* accSymbol;
};
IlvSymbol* TemperatureWatcher::tempSymbol;
IlvSymbol* TemperatureWatcher::accSymbol;
ユーザーによる編集時に、Thermometer 値の更新方法を定義する必要があります。changeValues メソッドは、プロトタイプのインスタンスのアトリビュート値と Thermometer メンバー間に、1 対 1 の関係を確立します。
// Method handling with user input and updating the application.
IlBoolean
TemperatureWatcher::changeValues(const IlvValue* v, IlvUShort n)
{
if(locked()) return IlFalse;
for (IlUInt i=0;i<n;i++) {
if (v[i].getName() == accSymbol)
getThermometer()->acceleration = (IlUInt) v[i];
// You do not want the temperature value to be editable by the user.
// If this was the case, the following code would simply be added:
// else if (v[i].getName() == tempSymbol)
// getThermometer()->temperature = (IlFloat) v[i];
}
return IlTrue;
}
どのプロトタイプ・アトリビュートを介して温度計の値がユーザー・インターフェースに反映されるのか、指定する必要があります。ここでは queryValues メソッドが、Thermometer アトリビュートと、それを示すプロトタイプのインスタンス値の間に、1 対 1 の対応を確立します。
// Method that synchronizes the group to the application values.
void TemperatureWatcher::queryValues(IlvValue* v, IlvUShort n) const
{
for (IlUInt i=0;i<n;i++) {
if (v[i].getName() == tempSymbol)
v[i] = getThermometer()->temperature;
else if (v[i].getName() == accSymbol)
v[i] = getThermometer()->acceleration;
}
}
アプリケーション・オブジェクトを表示にリンクする
この温度計アプリケーションのユーザー・インターフェースをインスタンス化するため、それを監視する myThermometer のインスタンスを作成します。メイン・プログラムで次に示すコードを、グループ・ホルダーから myThermometer グループの取得後に (ただしメイン・ウィンドウの表示前に) 追加します。
TemperatureWatcher watch(tempRep, &myThermometer);
watch.update();
IlvTimer timer(display, 0, 200, TimerProc, &watch);
timer.run();
このタイマーは定期的に温度計インスタンスの状態をチェックし、必要ならば表示を更新します。
アプリケーション・オブジェクトと表示の同期化
最後に、メイン・プログラムの前に非同期更新ルーチンを定義する必要があります。
static void
TimerProc(IlvTimer*, IlvAny arg)
{
TemperatureWatcher* watcher=(TemperatureWatcher*) arg;
watcher->update();
}
TemperatureWatcher は定期的に Thermometer オブジェクトの現在値に従って、それ自体を更新します。
メモ: Observer/Observable デザイン・パターンに従う Thermometer クラスの振る舞いを持たせたり、さらにその変更を他のオブジェクトに通知するなど、その他のメカニズムも実装できます。このメソッドの方がわずかに効率的です。$ILVHOME/samples/protos にあるサンプルは、このテクニックを実装しています。ただし、トリガーされた非同期オブザーバーの使用は、リアルタイム制約のあるアプリケーションの実装には役立ちます。厳しい時間的制約に合わせる必要がある場合は、ユーザー・インターフェースの更新頻度を調整できます。

Version 5.6
Copyright © 2012, Rogue Wave Software, Inc. All Rights Reserved.