イベントの管理:オブジェクト・インタラクター
オブジェクト・インタラクターは、それが付加されているグラフィック・オブジェクトについて、ユーザー・イベントのフィルターリングを行います。適切なイベントが続いて発生すると、オブジェクト・インタラクターはグラフィック・オブジェクトから目に見える応答をトリガーします。この応答をオブジェクトの振る舞いと呼びます。
Rogue Wave® Views は、包括的な定義済みオブジェクト・インタラクターを備えています。Rogue Wave Views で定義されていない特殊な機能が必要な場合は、インタラクター・クラスの 1 つをサブタイプ化し、そのメンバー関数 handleEvent を必要な機能と置き換えます。
図 9.1 インタラクターをオブジェクトに付加する
IlvInteractor クラスは、振る舞いをオブジェクトに関連付けます。
メモ: これらのオブジェクト・インタラクターは、エディター作成用ではありません。対話的エディターの作成には、個々のオブジェクトではなくビュー全体に関連付けられている Rogue Wave ViewsManager を使用します。 |
オブジェクト・インタラクターの詳細については、以下を参照してください。
オブジェクト・インタラクターの使用
オブジェクト・インタラクターを処理するメンバー関数は次のとおりです。
下記の例では、定義済みの Rogue Wave Views インタラクターを
IlvLabel グラフィックと関連付けています。このオブジェクト上でマウスの左ボタンをクリックしてオブジェクトを移動させるのは、
IlvMoveInteractor クラスのインスタンスです。
IlvRect size(0, 0, 300, 300); IlvContainer* cont = new IlvContainer(display, "Cont", "My Window", size, IlTrue, IlFalse); IlvLabel* label = new IlvLabel(display, IlvPoint(100,100), "Hello world!"); cont->addObject(label); label->setInteractor(IlvInteractor::Get("Move")); |
スタティック・メンバー関数の IlvInteractor::Get は、「Move」というオブジェクト・インタラクターの固有インスタンスを返します。通常はインタラクターのコントラクタを直接呼び出してインタラクターを作成するのではなく、このスタティック・メンバー関数を使用します。これはほとんどのオブジェクト・インタラクターが多数のグラフィック・オブジェクトで同時に共有できるためです。
新しい IlvInteractor サブクラスの登録
IlvInteractor クラスをサブタイプ化する場合、スタティック・メンバー関数
IlvInteractor::Get を使用するためにサブクラスを登録する必要があります。下記は、
MyInteractor クラスの
IlvInteractor クラスをサブタイプ化するヘッダー・ファイルのサブクラス登録部分です。
class MyInteractor : public IlvInteractor { public: IlBoolean handleEvent(IlvGraphic* obj, IlvEvent& event, IlvTransformer* t); ... DeclareInteractorTypeInfo(MyInteractor); }; |
ここで クラスの永続化と登録を行う
DeclareInteractorTypeInfo マクロを呼び出す行を追加しています。このマクロにより
IlvInputFile への参照を必要とするコンストラクター、
MyInteractor への参照を必要とするコピー・インストラクタ、インタラクター・インスタンスの保存に必要な
write メンバー関数を定義しなくてはならなくなります。当然、コンストラクターと write 関数は一致する必要があります。これは
IlvGraphic クラスの場合と同様です。
インタラクターに保存する追加情報がない場合は、DeclareInteractorTypeInfoRO マクロを使用します。これは write メンバー関数を定義する必要がありません。
この例では保存する追加情報はありませんが、完全な例を提供するという観点から、保存、読み込みを行うダミーの整数値を使用しています。
MyInteractor::MyInteractor(IlvInputFile& file) : IlvInteractor(file) { IlInt i; file.getStream() >> i; // Read a (dummy) integer value } IlvInteractor* MyInteractor::write(IlvOutputFile& file) { file.getStream() << (IlInt)0; } |
DeclareInteractorTypeInfoRO を使用した場合、コンストラクターは空になり、write 関数は定義されません。
ソース・ファイルにあるその他の関数の本文外で、次の 2 つのインストラクションを書く必要があります。
IlvPredefinedInteractorIOMembers(MyInteractor) IlvPredefinedInteractorIOMembers は入力ファイルからコンストラクターを呼び出して、copy メンバー関数を定義するプロキシ関数を生成するマクロです。
IlvRegisterInteractorClass(MyInteractor, IlvInteractor); IlvRegisterInteractorClass は MyInteractor クラスを新しく利用可能なインタラクター・クラスとして登録するマクロです。2 つ目のパラメーターは親クラスの名前でなければなりません。
定義済みのオブジェクト・インタラクター
定義済みのオブジェクト・インタラクターをプログラミングする場合に役に立つクラスがいくつかあります。
例:インタラクターとアクセラレーターのリンク
以下の例では、下記のウィンドウとその中にある 2 つの描画を作成します。
図 9.2 2 つのオブジェクトを含むコンテナー
すなわち、トップ・ウィンドウのコンテナーを作成し、オブジェクトを 2 つ追加します。これらは灰色の楕円と円弧です。ただし、これらのオブジェクトを実際にコンテナーに配置する前に、形状変更インタラクターを作成し、マウスを使用してグラフィック・オブジェクトの形状を変更します。このインタラクター 1 つを 2 ヶ所で使用します。
楕円をコンテナーに追加した直後に、形状変更インタラクターをこのオブジェクトに関連付けます。
円弧をコンテナーに追加した直後に、同じ形状変更インタラクターをこのオブジェクトに関連付けます。
これで 2 つのグラフィック・オブジェクトのいずれかをクリックすると、形状変更インタラクターにより、マウスをドラッグして選択したオブジェクトの形状を変更できます。
さらに、2 つのオブジェクトと固有のインタラクターを作成した後、コンテナーにアクセラレーターを作成し、オブジェクトでマウスの左ボタンをダブルクリックしてその情報を表示させます。
楕円をダブルクリックすると、次のメッセージが表示されます。
Object is an IlvFilledEllipse円弧をダブルクリックすると、次のメッセージが表示されます。
Object is an IlvArcここでは
PrintType という 3 つの引数を持つ関数を作成し、これらのメッセージを生成します。この関数には定義済みの
IlvContainerAction タイプが備わっています。この関数の名前は、
addAccelerator メンバー関数を呼び出す最初の引数としてコンテナーに与えられます。
次に、デモ用プログラム全体を示します。例を短くするために、プログラムの終了部分は記述していません。
#include <ilviews/contain/contain.h> #include <ilviews/graphics/ellipse.h> #include <ilviews/graphics/arc.h> #include <ilviews/graphics/inter.h> static void PrintType(IlvContainer*, IlvEvent&, IlAny); int main(int argc, char* argv[]) { IlvDisplay* display = new IlvDisplay("Demo", "", argc, argv); if (!display || display->isBad()) { IlvFatalError("Couldn't open display"); delete display; IlvExit(-1); } IlvContainer* container = new IlvContainer(display, "Demo", "Demo", IlvRect(0, 0, 200, 200), IlTrue, IlFalse); IlvInteractor* reshape = IlvInteractor::Get("Reshape"); IlvGraphic* object = new IlvFilledEllipse(display, IlvRect(150, 50, 40, 20)); container->addObject(object); object->setInteractor(reshape); container->addObject(object = new IlvArc(display, IlvRect(10, 150, 40, 40), 0., 60.)); object->setInteractor(reshape); container->addAccelerator(PrintType, IlvDoubleClick, IlvLeftButton); container->show(); IlvMainLoop(); return 0; } static void PrintType(IlvContainer* view, IlvEvent& event, IlAny) { IlvGraphic* object = view->contains(IlvPoint(event.x(), event.y())); if (object) IlvPrint("Object is an ‘%s’\n" , object->className()); } |
例の分析
このセクションでは、上記の例で使用したコードについて説明します。
static void PrintType(IlvContainer*, IlvEvent&, IlAny);
ユーザー定義の PrintType 関数がアクセラレーターにより呼び出されます。アクセラレーターはユーザーがグラフィック・オブジェクト上でマウスの左ボタンをクリックすると起動します。PrintType 関数の署名は、IlvContainerAction と呼ばれるタイプに対応しています。
IlvContainer* container = new IlvContainer(display, "Demo", "Demo",
IlvRect(0, 0, 200, 20), IlTrue, IlFalse);
コンテナーが上位レベル・ビューとして作成されます。
IlvInteractor* reshape = IlvInteractor::Get("Reshape");
形状変更インタラクターが特定されます。これは <ilviews/graphics/inter.h >を追加した際に自動的に登録されています。
IlvGraphic* object = new IlvFilledEllipse(display, IlvRect(150,50, 40,20));
container->addObject(object);
塗りつぶし楕円が作成され、コンテナーに追加されます。
object->setInteractor(reshape);
形状変更インタラクターを塗りつぶし楕円に関連付けます。
container->addObject(object =
new IlvArc(display, IlvRect(10, 150, 40, 40), 0., 60.));
円弧をコンテナーに追加します。
object->setInteractor(reshape);
形状変更インタラクターを円弧に関連付けます。
container->addAccelerator(PrintType, IlvDoubleClick, IlvLeftButton);
アクセラレーターをコンテナーに追加します。このアクセラレーターは、ユーザーがオブジェクト上でマウスの左ボタンをクリックするたびに、PrintType というユーザー定義の関数に適用されます。
static void PrintType(IlvContainer* view, IlvEvent& ev, IlAny) { IlvGraphic* object = view->contains(IlvPoint(ev.x(), ev.y())); if (object) IlvPrint("Object is a '%s’\n", object–>className()); } |
これはユーザー定義の PrintType 関数を実際に実装するものです。ここでは IlvContainer::contains メンバー関数を呼び出して、マウス・ポインターの下にあるオブジェクトにアクセスします。ここでは IlvPrint 関数を使用して、この例の移植性を確実にしています。
Version 6.0
Copyright © 2015, Rogue Wave Software, Inc. All Rights Reserved.