アプリケーション・オブジェクトへプロトタイプをリンクする
このセクションでは、プロパティーをアプリケーション・オブジェクトにリンクさせるのに使用する 3 つのメソッドについて説明します。
値の直接設定: 単にアプリケーションからビューに値を渡す場合は、これがもっとも簡単な方法です。
プロト・メディエーターの使用: これにより、アプリケーション・クラスをプロトタイプにリンクさせるファクトリー・オブジェクトを構築でき、その結果、動的アプリケーションのインターフェースを自動的に作成します。
値の直接設定
サンプル base_feed (<ILVHOME>/samples/protos ディレクトリーに含まれている) は、アプリケーションからインターフェースの駆動方法を示しています。プロトタイプのインスタンスを含むパネルをダウンロードする、あるいはマネージャーあるいはコンテナーでインスタンスを作成して、編集するインスタンスを取得します。
IlvGroupHolder* groupHolder = IlvGroupHolder::Get(manager);
IlvGroup* myThermometer= groupHolder->getGroup(OthermometerO);
次に、その値を IlvGroup::changeValue メソッドで変更します。
if (myThermometer)
myThermometer->changeValue(IlvValue(?temperature?,(IlUInt) 20)));
グループ・メディエーターの使用
グループ・メディエーター (クラス
IlvGroupMediator) は、アプリケーションのオブジェクトをプロトタイプに接続するために使用され、オブジェクト (詳細設定とも呼ばれる) のインタラクティブ・グラフィック・エディターとして機能します。サンプル
inspector および
synoptic (
<ILVHOME>/samples/protos ディレクトリーに含まれる) は、グループ・メディエーターを実装し、ベースラインとして使用されます。
次のコード・サンプルは、ユーザー・インターフェースとアプリケーション・コードを明確に分離するアプリケーションの開発方法を示しています。Machine ベース・クラスおよび Boiler 特殊クラスを含むアプリケーションを想定します。
class Machine { // The base class of most application objects.
protected:
list<MachineObserver* > observers;
};
class MachineObserver { // A notification mechanism serving as a
// generic communication means between objects.
public:
void observe(Machine* m) { m->observers.append(this); }
virtual void notify (Machine*);
};
class Boiler :public Machine { // The class for which you want
// to create an object inspector.
public:
// Temperature is an attribute you want the user to have control of.
void set_temperature(float) { ...
for each observer in observers
observer->notify(this);
}
float get_temperature();
};
これらのクラスは、シミュレーション、プロセス・コントロールあるいはコンピューター上の操作を、あらゆる種類のインタラクティブまたはグラフィックの振る舞いから独立して行います。グループ・メディエーターにより、かなり複雑であると推定されるアプリケーション・クラス依存を導入することなく、グラフィカル・ユーザー・インターフェースを Boiler に実装することができます。
このためには、グラフィック表示を扱う
IlvGroupMediator のサブクラスおよび
Boiler クラスの機械のユーザー・インタラクションを作成します。
class BoilerUI :public IlvGroupMediator, public MachineObserver {
public:
BoilerUI(IlvGroup* ui, Boiler* b) :IlvGroupMediator(ui, b) {
MachineObserver::observe(b);
if (!temperatureSymbol)
temperatureSymbol=IlvGetSymbol(?temperature?);
}
Boiler* boiler() { return (Boiler*) getObject(); }
void queryValues(IlvValue* vals, IlUInt) const {
if (vals[0].getName() == temperatureSymbol))
vals[0] = boiler()->get_temperature();
}
void changeValues(const IlvValue* vals, IlUInt) {
if (vals[0].getName() == temperatureSymbol))
boiler->set_temperature(vals[0]);
}
void notify(Machine*) { update(); }
static IlvSymbol* temperatureSymbol;
};
このクラスは、プロトタイプ・インスタンスとアプリケーション・オブジェクト間のブリッジとして機能します。4 つのメソッドを定義します。
コンストラクターはリンクを確立し、
observe(b) ステートメントはアプリケーションに、ボイラーに生じた内部変更を通知するように宣言します。
オブジェクトのアトリビュートにユーザーが変更を行ったときに呼び出される
changeValue() メソッド。これは、オブジェクトに温度値を更新するように通知します。その他のアトリビュートも処理します。
プロトタイプが値を更新する必要があるときに呼び出される
queryValue() メソッド。オブジェクトの内部値を問い合わせ、ユーザー・インターフェースに伝達します。
オブジェクトの内部アトリビュートが変更されたときに、この変更をユーザー・インターフェースに反映させるためにアプリケーション内部から明示的に呼び出す必要がある
notify() メソッド。
Boiler::set_temperature() への呼び出しは、自動的にすべてのオブザーバーに通知されます。つまり、
notify() メソッドは、明示的に呼び出される必要はありません。このように、Observer/Observable デザイン・パターンを実装しない他のアプリケーションでは、内部コードの他の部分から
notify() を呼び出す場合があります。
メディエーター・クラスが定義されると、アプリケーションのオブジェクトをボイラーの詳細設定として使用されるプロトタイプ・インスタンスへ動的にリンクさせることができます。
IlvGroup* myBoilerInspector = groupHolder->getGroup("BoilerInspector");
BoilerUI* myBoilerUI = new BoilerUI(myBoilerInspector, myBoiler);
プロトタイプで詳細設定されているアプリケーション・オブジェクトはいつでも変更できます。
myBoilerUI->setObject(myOtherBoiler);
この機構は、いくつかのアプリケーション特有のコーディングを必要としますが、それは非常に一般的なものです。どのようなアプリケーション・データ構造もこれを使用するように適合できます。メディエーター・クラスのデザインが終わると、ユーザー・インターフェースおよびアプリケーションは完全に独立したエンティティーになります。各々を、別個に開発、保守できます。ユーザー・インターフェースは、Rogue Wave Views Studio およびあらゆるアプリケーション開発環境を使用するアプリケーションを使用して開発されます。
グループ・メディエーターは、ユーザー・インターフェースの不必要な更新を防ぐために使用するロック機構も備えています。上の例では、ボイラー set_temperature メソッドは、BoilerUI の notify() メソッドを呼び出してユーザー・インターフェースを更新します。値の変更は、UI から生じるため、この最後の更新は不必要な場合もあります。ロックしたフラグがそのような更新を防ぐかどうかをテストするには、次のようにします。
void BoilerUI::changeValues(const IlvValue* vals, IlUInt) {
if (locked()) return;
if (vals[0].getName() == temperatureSymbol))
boiler->set_temperature(vals[0]);
}
プロト・メディエーターの使用
プロト・メディエーター (クラス
IlvProtoMediator) は、
IlvGroupMediator のサブクラスで任意のクラスのプロトタイプ・インスタンスを動的に作成し、これらをマネージャーあるいはコンテナーに配置するために使用されます。目的は、各メイン・アプリケーション・クラス用に特定プロトタイプをデザインすることです。オブジェクトがアプリケーションで作成されると対応するプロトタイプがインスタンス化され、マネージャーに配置されます。これにより、アプリケーションの機能的コアからユーザー・インターフェース・デザインを分離させて、アプリケーション全体用のグラフィカル・ユーザー・インターフェースを作成することができます。
<ILVHOME>/samples/protos ディレクトリーからの次のサンプルは、このデザイン・パターンを実装しています。(航空管制シミュレータを構築するための
interact_synoptic および製造プラント・シミュレータを構築するための
synoptic)
たとえば、同じベース・アプリケーションを想定して (
Machines および
Boilers)、ユーザーが同時に表示させ編集する各
Boiler インスタンスを設定するとしましょう。
IlvProtoMediator のサブクラスを作成します。
class BoilerUI :public IlvProtoMediator, public MachineObserver {
public:
BoilerUI(IlvManager*m,Boiler*b)
:IlvProtoMediator(m,"BoilerPrototype",b)
{
observe(b);
IlvSymbol* vals[2] = {
IlvGetSymbol( "x"), IlvGetSymbol("y") };
update(vals); // Sets the position of the current instance.
// The application must have a way of specifying where to place
// the object.Alternatively, you can handle the placement by
// explicitly setting the x and y values of the BGO.
install(m); // Place the prototype in the manager
}
// Other methods are the same as the BoilerUI using the GroupMediator.
};
これで、アプリケーションは、その内部オブジェクトを作成するとすぐにプロトタイプ・インスタンス生成を行うグローバルな「ユーザー・インターフェース・ファクトリー」を持つことができます。このファクトリーのコードは、次の擬似コードのようになります。
class myApplication {
list<Boiler*> boilers;
void initUI (IlvManager* m) {
for each machine in boilers
new BoilerUI(m, machine);
}
void add_boiler(Boiler* b) {
boilers.append(b);
new BoilerUI(getManager(), b);
}
};
Version 6.0
Copyright © 2015, Rogue Wave Software, Inc. All Rights Reserved.