前のページ次のページ上に戻るホーム SophiaFramework UNIVERSE 5.3

9.2. レスポンダシステムの構成要素

レスポンダシステムには、 レスポンダツリー、ルートレスポンダ、親子・姉妹関係、レスポンダ空間、領域、 状態、イベント、イベントループ、トレーサ、ハンドラなどの構成要素があります。

この節では、これらのレスポンダシステムの構成要素について解説します。

9.2.1. レスポンダツリー

レスポンダツリーとは、 複数個のレスポンダから階層的に構成される木構造のことです。

木構造の頂点に位置するレスポンダは、 ルートレスポンダと呼びます。

レスポンダツリーは、アプリの GUI(グラフィカルユーザーインターフェース)を構成し、 以下の順序関係でレスポンダ空間に描画されます。

  1. 子レスポンダ親レスポンダよりも前面にあります。
  2. 姉妹レスポンダでは、姉レスポンダは妹レスポンダよりも前面にあります。
  3. 姉レスポンダは妹レスポンダの子レスポンダよりも前面にあります。

[Note] 姉妹レスポンダ間の順序関係について

姉妹レスポンダ間の順序関係は、 親レスポンダ子レスポンダを設定した順序を表します。

3 つのレスポンダ A、B、X があり、最初に A を X の子レスポンダにし、次に B を X の子レスポンダにした場合、 A は B の姉レスポンダであり、逆に B は A の妹レスポンダです。

この順序関係(姉妹関係)は、 SFYResponder::ToFront / SFYResponder::ToNthForward / SFYResponder::ToBack / SFYResponder::ToNthBackward 関数によって変更可能です。

例えば、上記の B に対して SFYResponder::ToFront を呼び出せば、 B は A の姉レスポンダになります(または、A は B の妹レスポンダになります)。

[Note] レスポンダツリーの描画について

レスポンダツリーをレスポンダ空間に描画するには、 レスポンダツリーの頂点にあるルートレスポンダ描画エンジンSFYRenderer)を関連付ける必要があります。

SFY アプリでは、 SFYApplication::SFYApplication コンストラクタの処理により、 予め描画エンジンが関連付けられた SFYApplication クラスが内部で保持するルートSFZRoot)をルートレスポンダとして利用するので、この処理は省略されます。

[Tip] ToFront 関数

ボタンやラベルなどのコントロールを子レスポンダとして持つウィンドウの SFYResponder::ToFront 関数を呼び出すと、 ウィンドウの子レスポンダも一緒に最前面に移動します。

なお、SFYResponder::ToFront 関数を呼び出したレスポンダは同じ姉妹レスポンダの中で一番上の姉レスポンダとなります。

図 9.3. レスポンダツリーの構造


レスポンダツリーの構造

SFZWindow(参照:右側の不完全なレスポンダツリー)は、 SFZRoot(参照:左側の完全なレスポンダツリー)を親レスポンダに設定するまでの間は親レスポンダが存在しないのでルートレスポンダです。

例 9.4. レスポンダツリーの作成

SFCError USRApplication::MakeTree(Void)
{
    SFZRootSmp root;
    SFZDialogSmp dialog;
    SFZTextButtonControlSmp button;
    SFZWindowSmp window;
    SFZTextLabelControlSmp label;
    SFCError error(SFERR_NO_ERROR);

    // SFYApplication クラスが内部に保持するルートを取得する
    if ((root = GetThis() != null) { 

        // ダイアログを生成する
        if ((dialog = SFZDialog::NewInstance(&error)) != null) {

            // ダイアログの親レスポンダをルートに設定する
            if ((error = dialog->SetParent(root)) == SFERR_NO_ERROR) {

                // テキストボタンコントロールを生成する
                if ((button = SFZTextButtonControl::NewInstance(&error)) != null) {

                    // テキストボタンコントロールの親レスポンダをダイアログに設定する
                    if ((error = button->SetParent(dialog)) == SFERR_NO_ERROR) {

                        // ...(省略)...
                    }
                }
            }
        }

        if (error == SFERR_NO_ERROR) {

            // ウィンドウを生成する
            if ((window = SFZWindow::NewInstance(&error)) != null) {

                // ウィンドウの親レスポンダをルートに設定する
                if ((error = window->SetParent(root)) == SFERR_NO_ERROR) {

                    // テキストラベルコントロールを生成する
                    if ((label = SFZTextLabelControl::NewInstance(&error)) != null) {

                        // テキストラベルコントロールの親レスポンダをウィンドウに設定する
                        if ((error = label->SetParent(window)) == SFERR_NO_ERROR) {

                            // ...(省略)...
                        }
                    }
                }
            }
        }
    }

    return error;
}
[Note] 注意

SFYApplication クラスは、 内部にルートSFZRoot)を保持しています。

9.2.2. ルートレスポンダ

ルートレスポンダとは、 レスポンダツリーの頂点に位置するレスポンダです。

ルートレスポンダに配信エンジンSFYDistributer)を関連付けると、 レスポンダツリー上のレスポンダの有効状態は ON になり、 レスポンダツリーにイベントを配信することが可能になります。

ルートレスポンダに描画エンジンSFYRenderer)を関連付けると、 レスポンダツリーを描画することが可能になります。

図 9.4. ルートレスポンダと配信エンジン・描画エンジンの関係

ルートレスポンダと配信エンジン・描画エンジンの関係
[Note] 注意

ウィンドウやコントロールなどのレスポンダも、 作成してからレスポンダツリーに接続されるまでは親レスポンダが存在しないので形式上はルートレスポンダです。 しかし、デフォルトのルート以外のレスポンダに配信エンジンと描画エンジンを設定することはほとんどありません。

例 9.5. ルートへの配信エンジンと描画エンジンの設定

SFCError USRApplication::MakeRoot(Void)
{
    SFYDistributer _distributer;  // 配信エンジン
    SFYRenderer _renderer;        // 描画エンジン
    SFZRootSmp _root;             // ルート
    SFCError error(SFERR_NO_ERROR);

    // ********************************************************************************
    // 以下の処理は SFYApplication クラスのコンストラクタ内で実装済みです。            
    // 一般のアプリ開発では、実装する必要はありません。                                
    // ********************************************************************************

    // 配信エンジンを初期化する
    error = _distributer.Initialize();
    if (error == SFERR_NO_ERROR) {

        // 描画エンジンを初期化する
        // ※デバイス画面領域(携帯電話の画面領域)がレスポンダ空間となる
        error = _renderer.Initialize();
        if (error == SFERR_NO_ERROR) {

            // ルートを生成する
            if ((_root = SFZRoot::NewInstance(&error)) != null) {

                // ルートに配信エンジンを設定する
                _root->SetDistributer(&distributer);

                // ルートに描画エンジンを設定する
                _root->SetRenderer(&renderer);

                // ルートの実領域を設定する
                // ※1. 親レスポンダが存在しないルートはレスポンダ空間内に実領域を設定する
                // ※2. _root->GetSuitableBound() はレスポンダ空間(=デバイス画面領域)を返す
                // ※3. ルートの実領域はデバイス画面領域に設定される
                _root->SetRealBound(_root->GetSuitableBound());

                // ルートの状態を「可視+活性+操作可能+フォーカス」にまとめて設定する
                _root->SetState(true, true, true, true);
            }
        }
    }

    return error;
}
[Tip] Tip

SFYApplication クラスは、 内部にルートSFZRoot)を保持しています。 SFYApplication::SFYApplication コンストラクタの処理により、 このルートには配信エンジン描画エンジンが関連付けられます。

通常、このルートをアプリの GUI を構成する レスポンダツリーのルートレスポンダとして使用するので、 上記コードを実装する必要はありません。

参照: SFZRoot | SFYDistributer | SFYRenderer | SFYResponder::SetDistributer | SFYResponder::SetRenderer

9.2.3. 親レスポンダ

親レスポンダとは、自レスポンダを所有している親となるレスポンダのことです。

ウィンドウ内にボタンコントロールが存在する場合、 ウィンドウはボタンコントロールの親レスポンダです。

GUI コンポーネントとして画面に配置するとき、 親レスポンダは子レスポンダよりも背面に配置されます。

[Tip] Tip

親レスポンダは SFYResponder::SetParent 関数を使用して設定します。

親レスポンダを設定すると、 レスポンダは親レスポンダが所属しているレスポンダツリーに接続されます。

図 9.5. 親レスポンダとの包含関係

親レスポンダとの包含関係

例 9.6. 親レスポンダの設定

SFCError USRResponder::SetButtonParent(Void)
{
    SFZWindowSmp window;
    SFZTextButtonControlSmp button;
    SFCError error(SFERR_NO_ERROR);

    // ...(省略)...

    // button の親レスポンダを window に設定する
    if ((error = button->SetParent(window)) == SFERR_NO_ERROR) {

        // ...(省略)...
    }

    return error;
}

例 9.7. 親レスポンダのクリア

SFCError USRResponder::ClearButtonParent(Void)
{
    SFZTextButtonControlSmp button;
    SFCError error(SFERR_NO_ERROR);

    // ...(省略)...

    // SFYResponderSmp::EmptyInstance() を指定して親レスポンダをクリアする
    if ((error = button->SetParent(SFYResponderSmp::EmptyInstance())) == SFERR_NO_ERROR) {

        // ...(省略)...
    }

    return error;
}
[Tip] Tip

親レスポンダをクリアするには、レスポンダの SFYResponder::SetParent 関数の引数に SFYResponderSmp::EmptyInstance() を指定します。 この操作によりレスポンダはレスポンダツリーから分離されます。

9.2.4. 子レスポンダ

子レスポンダとは、 自レスポンダが所有している子となるレスポンダのことです。

ウィンドウ内にボタンコントロールが存在する場合、 ボタンコントロールはウィンドウの子レスポンダです。

GUI コンポーネントとして画面に配置するとき、 子レスポンダは親レスポンダよりも前面に配置されます。

図 9.6. 子レスポンダとの包含関係

子レスポンダとの包含関係

例 9.8. 子レスポンダの検索

SFYResponderSmp USRResponder::SearchChild(SInt32 index) const
{
    // 可視の子レスポンダの中で前面から index 番目の子レスポンダを検索する
    // この他にもいくつかの検索方法が利用可能
    return GetChildForward(index, true, false, false, false);
}

参照: SFYResponder::GetChildBack | SFYResponder::GetChildFront | SFYResponder::GetChildBackward | SFYResponder::GetChildForward | SFYResponder::GetChildCount

9.2.5. 姉妹レスポンダ

姉妹レスポンダとは、 自レスポンダと同じ親レスポンダを持つ姉妹となるレスポンダのことです。

GUI コンポーネントとして画面に配置するとき、 姉レスポンダは妹レスポンダよりも前面に配置されます。

図 9.7. 姉妹レスポンダとの包含関係

姉妹レスポンダとの包含関係

例 9.9. 姉妹レスポンダの検索

SFYResponderSmp USRResponder::SearchNextSister(Void) const
{
    SFYResponderSmp parent;
    SFYResponderSmp result;

    // 自レスポンダと同じ親レスポンダを持つすべての姉妹レスポンダの中で
    // 自レスポンダの次の姉妹レスポンダを検索する
    if ((parent = GetParent()) != null) {

        if ((index = GetNthBackward(false, false, false, false)) > 0) {

            result = parent->GetChildBackward(index - 1, false, false, false, false);
        }
    }

    return result;
}

参照: SFYResponder::GetChildBackward | SFYResponder::GetChildBack | SFYResponder::GetNthBackward | SFYResponder::ToNthBackward | SFYResponder::IsNthBackward | SFYResponder::ToBack | SFYResponder::IsBack | SFYResponder::GetChildForward | SFYResponder::GetChildFront | SFYResponder::GetNthForward | SFYResponder::ToNthForward | SFYResponder::IsNthForward | SFYResponder::ToFront | SFYResponder::IsFront

9.2.6. レスポンダ空間

レスポンダ空間とは、 レスポンダツリーを描画する矩形領域のことです。

レスポンダ空間は、 描画エンジンの初期化時に、 デバイス画面領域(SFXGraphics::GetDeviceRectangle 関数の戻り値)に設定されます (参照: SFYRenderer::Initialize 関数)。

レスポンダツリーをレスポンダ空間に描画するには、 ルートレスポンダに描画エンジンを関連付ける必要があります。

SFY アプリ開発では、 SFYApplication クラスが内部で保持する、 既に描画エンジンが関連付けられたルートSFZRoot)をルートレスポンダとして利用します。

ルートの実領域は、 レスポンダ空間の左上端を原点とする相対座標系の矩形領域として表され、 デフォルトではレスポンダ空間(=デバイス画面領域)に一致します。

[Note] レスポンダ空間の変更

レスポンダ空間は、 デバイス画面領域(SFXGraphics::GetDeviceRectangle 関数の戻り値)に一致します。 この領域を変更するには、デバイス画面のディスプレイ設定を変更した後に描画エンジンを再初期化する必要があります。

参照: レスポンダ空間をフルスクリーンモードにする方法

9.2.7. 実領域

実領域とは、 親レスポンダのローカル領域内に表示されるレスポンダの矩形領域 (可視領域)です。

この領域は、 親レスポンダのローカル領域の左上端を原点とする相対座標系を使用して表されます。

レスポンダの内容は、 実領域でクリッピングされて親レスポンダのローカル領域に表示されます。

[Tip] Tip

実領域は SFYResponder::SetRealBound 関数を使用して設定します。

[Note] 注意

実領域のサイズは、 グローバル領域のサイズと一致します。

図 9.8. 実領域の位置関係


実領域の位置関係

※実領域は、親レスポンダのローカル領域の左上端を原点とする相対座標系の矩形 (SFXRectangle)として表されます。

例 9.10. 最適な領域を取得してから実領域を設定する方法

Void USRResponder::SetButtonBound(Void)
{
    SFZTextButtonControlSmp button;

    // ...(省略)...

    // テキストボタンコントロールのテキストを設定する
    button->SetText("Text Button");

    // テキストボタンコントロールの最適な領域を取得してから実領域を設定する
    button->SetRealBound(button->GetSuitableBound().SetOrigin(10, 10));

    // ...(省略)...

    return;
}
[Tip] Tip

SFYResponder::GetSuitableBound 関数を利用すれば、 テキストボタンコントロールに設定されたテキスト、フォントなどの情報から最適な領域を取得できます。

この関数で得られる領域の始点はデフォルトで (0, 0) なので、 必要に応じて SFXRectangle::SetOrigin / SFXRectangle::Offset 関数などを利用して最適な場所に配置します。

[Warning] 実領域の初期値

NewInstance 関数を実行した直後、 実領域は SFXRectangle(0, 0, 0, 0) です。 子レスポンダを配置するには、 SFYResponder::SetRealBound 関数を使用して実領域を設定する必要があります。

[Note] ルートの実領域

SFYApplication クラスが内部に保持するルートSFZRoot)には親レスポンダが存在しません。 ルートの実領域は、 レスポンダ空間の左上端を原点とする相対座標系の矩形領域として表されます。

SFYApplication::SFYApplication コンストラクタ内の処理により、 ルートの実領域はレスポンダ空間と同じ矩形領域(デバイス画面領域)に初期設定されます。

[Tip] Tip

通常、ルートの実領域を設定したり変更する必要はありません。

[Caution] 実領域と仮想領域

SFYResponder::SetRealBound 関数を使用して実領域を小さくすると、 仮想領域は実領域よりも大きくなります。

[Tip] Tip

実領域よりも大きな仮想領域を持つ必要のないレスポンダでは、 SFYWidget::HandleBoundReal 関数をオーバーライドして仮想領域を実領域に一致させるとよいでしょう。

SFYControl::HandleBoundReal 関数は仮想領域を実領域に一致させます。

9.2.8. ローカル領域

ローカル領域とは、 レスポンダの全領域の左上端を原点とする座標系を使用して表した矩形領域です。

レスポンダの描画ハンドラは、 レスポンダのローカル領域内でローカル領域の相対座標系を使用して描画を行います。

[Tip] Tip

ローカル領域は SFYResponder::GetLocalBound 関数を使用して取得します。

[Note] 注意

ローカル領域のサイズは、 仮想領域のサイズと一致します。

図 9.9. ローカル領域の位置関係


ローカル領域の位置関係

※ローカル領域は、レスポンダ領域の左上端を原点とする相対座標系の矩形 (SFXRectangle)として表されます。

例 9.11. ローカル領域の描画

XANDLER_IMPLEMENT_VOIDRENDER(USRResponder, OnRenderRequest, invoker, reason, graphics)
{
    // ローカル領域全体を白色で塗り潰す
    graphics->FillRectangle(GetLocalBound(), SFXRGBColor(0xFF, 0xFF, 0xFF, 0x00));

    return;
}
[Warning] ローカル領域の初期値

NewInstance 関数を実行した直後、レスポンダのローカル領域は SFXRectangle(0, 0, 0, 0) です。 子レスポンダを配置するには、 SFYResponder::SetRealBound 関数を使用してレスポンダの実領域を設定する必要があります。

9.2.9. 仮想領域

仮想領域とは、 レスポンダのローカル領域実領域の左上端を原点とする相対座標系を使用して表した矩形領域です。

仮想領域の始点を移動すると、レスポンダ領域は実領域内でスクロールして表示されます。

仮想領域を設定しない場合、仮想領域は実領域に一致します。

[Tip] Tip

仮想領域は SFYResponder::SetVirtualBound 関数を使用して設定します。

[Note] 注意

仮想領域のサイズは、 ローカル領域のサイズと一致します。

図 9.10. 仮想領域と実領域の位置関係


仮想領域と実領域の位置関係

※仮想領域は、実領域の左上端を原点とする相対座標系の矩形 (SFXRectangle)として表されます。

図 9.11. 実領域と仮想領域の配置関係


実領域と仮想領域の配置関係

※仮想領域は実領域を含む必要があります。

例 9.12. レスポンダ領域をスクロールして表示する方法

Void USRResponder::ScrollVirtualBound(Void)
{
    // 現在の仮想領域を取得し、原点の Y 座標を 10 ピクセル分減算することにより
    // 仮想領域を 10 ピクセル分上にスクロールする
    SetVirtualBound(SFXRectangle(GetVirtualBound()).SubY(10));

    return;
}

9.2.10. グローバル領域

グローバル領域とは、 レスポンダの実領域を デバイス画面左上端を原点とする絶対座標系を使用して表した矩形領域のことです。

[Tip] Tip

グローバル領域は SFYResponder::GetGlobalBound 関数を使用して取得します。

[Note] 注意

グローバル領域は、 標準 BREW インターフェースにレスポンダの実領域を絶対座標系を使用して表して渡す場合に利用します。

グローバル領域のサイズは、実領域のサイズと一致します。

図 9.12. グローバル領域の位置関係


グローバル領域の位置関係

※グローバル領域は、 デバイス画面の左上端を原点とする絶対座標系の矩形(SFXRectangle)として表されます。

9.2.11. 可視領域

可視領域とは、 実際に利用者から見える、デバイス画面上のレスポンダ領域です。

一般に、レスポンダの実領域、 またはその部分領域になります。

レスポンダが不可視状態である場合、 可視領域は空の領域となります(レスポンダは可視領域を持ちません)。

レスポンダの実領域が親レスポンダの実領域やレスポンダ空間からはみ出る場合や、 レスポンダの実領域内の部分的な領域が他のレスポンダの隠れる場合は、 可視領域は実領域の部分的な領域となります。

[Note] 注意

SFYResponder::Invalidate 関数を呼び出して再描画領域を登録しても、 その領域がレスポンダの可視領域と交差領域を持たない限り、 描画イベントを受信しません。

9.2.12. 再描画領域

再描画領域とは、再描画が必要なレスポンダの矩形領域です。 SFYResponder::Invalidate 関数を利用して登録します。

[Note] 注意

再描画領域は、 ローカル領域左上端を原点とする座標系を使用して表します。

"SFYResponder::Render(false)" の実行により 描画エンジンを起動した場合、 再描画領域を登録したレスポンダだけが描画イベント受信の対象となります。

[Caution] 注意

再描画領域を登録していても、 その領域がレスポンダの可視領域と交差領域を持たない場合は、 描画イベントを受信しません。

[Note] 注意

詳細は、描画処理を参照してください。

9.2.13. 属性

レスポンダには背景が透過であるかどうかを表す透過属性があります。

透過属性のデフォルト値は false(非透過) ですが、 一部のレスポンダ(ラベルやラジオボタン、チェックボックスなど)では true(透過)にデフォルト設定されています。

属性が非透過である場合、 レスポンダの背景は SFYWidget::SetBackgroundColor 関数で設定された背景色(デフォルト: 白色)で塗り潰されます。

[Tip] Tip

透過属性は SFYResponder::SetProperty / SFYResponder::SetPropertyTransparent 関数を使用して設定します。

図 9.13. 透過属性の例: テキストラベルコントロール[SFZSingleTextLabelControl]とチェックボックスコントロール[SFZCheckboxControl]


透過属性の例: テキストラベルコントロール[SFZSingleTextLabelControl]とチェックボックスコントロール[SFZCheckboxControl]

テキストラベルコントロール[SFZSingleTextLabelControl]やチェックボックスコントロール[SFZCheckboxControl]では、 透過属性は true に設定されているので、左図のようにこれらのレスポンダの背景は塗り潰されません。

透過属性を false に設定すると、 背景は右図のように白色(デフォルト設定の場合)で塗り潰されます。

例 9.13. 透過属性の設定

Void USRResponder::SetTransparent(Void)
{

    // USRResponder の透過属性を true に設定する
    SetPropertyTransparent(true);

    return;
}

参照: SFYResponder::SetProperty | SFYResponder::SetPropertyTransparent | SFYWidget::SetBackgroundColor

9.2.14. 状態

レスポンダには優先順位付けされた 5 つの状態があります。

  1. 有効状態
  2. 可視状態
  3. 活性状態
  4. 操作可能状態
  5. フォーカス状態
[Note] 注意
有効状態が最も高い優先順位、フォーカス状態が最も低い優先順位を持ちます。

各状態の定義は以下の表の通りです。

表 9.2. レスポンダの状態

優先度 名称 解説
1 有効状態 有効 / 無効

レスポンダがイベントを受信できるかどうかを表します。

レスポンダは、 配信エンジンが接続されたレスポンダツリーに所属するときに限り有効です。

SFYResponder::Terminate 関数を呼び出すと、 レスポンダはレスポンダツリーから切り離され、「無効」の状態になります。

2 可視状態 可視 / 不可視

レスポンダが見えるかどうかを表します。

親レスポンダの実領域の外側にあるレスポンダや姉妹レスポンダに覆い隠されて描画されないレスポンダは、 不可視に設定しておくと描画速度が向上します。

3 活性状態 活性 / 不活性

レスポンダが操作対象になりえるかどうかの外観を表します。

レスポンダは不活性状態にあるとき、 ラベルテキストや枠線の色が薄くなったり、 立体的なレスポンダは平面的なデザインになったりします。

活性状態はレスポンダの外観にだけ効果をもたらします。

4 操作可能状態 操作可能 / 操作不能

レスポンダが操作可能かどうかを表します。

活性状態とは異なり、操作可能でも操作不能でもレスポンダの外観は同じです。

操作不能状態であるとき、 レスポンダはフォーカスされることはありません(操作対象になりません)。

5 フォーカス状態 フォーカス / 非フォーカス

レスポンダが操作対象になっているか(フォーカスされているか)どうかを表します。

フォーカス状態にあるとき、 フォーカス枠が描画されたりします。

フォーカス状態のフラグは、他のすべての状態フラグが true である場合に限り、 true に設定可能です。 また、他の状態のフラグが 1 つでも false に変更されると、 自動的に false に設定されます。

姉妹レスポンダの中では、高々 1 つのレスポンダにしかフォーカス状態フラグを true に設定できません。

操作可能な他の姉妹レスポンダのフォーカス状態フラグを true に設定すると、 それまでフォーカスされていたレスポンダのフォーカス状態フラグは自動的に false に設定されます。

フォーカス状態フラグが true であるレスポンダが破棄されたとき、 フォーカスは操作可能状態にある他の姉妹レスポンダに移動します。 具体的には、背面に操作可能状態にある姉妹レスポンダがある場合は、 1 つだけ背面にある、 フォーカス状態の以外の他のすべての状態フラグが true である姉妹レスポンダのフォーカス状態フラグが true になります。 そのような姉妹レスポンダが存在しない場合は、 1 つだけ前面にある、 フォーカス状態の以外の他のすべての状態フラグが true である姉妹レスポンダのフォーカス状態フラグが true になります。

なお、フォーカス状態フラグが true であるレスポンダのフォーカス状態フラグを false に変更した場合は、 どの姉妹レスポンダにもフォーカスは移動しません。

[Note] レスポンダの初期状態

NewInstance 関数を使用してインスタンスを生成した直後、 レスポンダの状態フラグは以下のように初期化されます。

  1. 有効状態フラグ: true
  2. 可視状態フラグ: false
  3. 活性状態フラグ: false
  4. 操作可能状態フラグ: false
  5. フォーカス状態フラグ: false

[Warning] 注意
  1. SFYResponder::Terminate 関数を呼び出して有効状態フラグが false に設定されたレスポンダに対して SFYResponder::Initialize 関数を呼び出して再初期化してはいけません。
  2. 有効状態フラグの値が false であるレスポンダにイベントを送信してはいけません。
    [Tip]

    デストラクタ内で処理をしているとき、 有効状態フラグの値は false なので自分自身にイベントを送信してはいけません。

図 9.14. 5 つの状態の例: テキストボタンコントロール[SFZTextButtonControl]

5 つの状態の例: テキストボタンコントロール[]
5 つの状態の例: テキストボタンコントロール[SFZTextButtonControl]

テキストボタンコントロール[SFZTextButtonControl]は状態に応じて外観が変化します。

図 9.15. 5 つの状態の例(拡大図): テキストボタンコントロール[SFZTextButtonControl]


5 つの状態の例(拡大図): テキストボタンコントロール[SFZTextButtonControl]

状態に応じて、テキストボタンコントロール[SFZTextButtonControl]を構成する要素の色が変化したり、 表示されたりされなかったりします。

  • 有効: 不可視状態なのでボタンは表示されません。
  • 有効+可視: ボタンは表示されますが、ボタンのベベル領域のライトカラーとダークカラーがベースカラーと同じになり平面的に見えます。また、ラベルと影の色も少し薄く表示されます。
  • 有効+可視+活性: ボタンのベベル領域のライトカラー、ダークカラー、ベースカラーが異なる色で表示され立体的に見えます。ラベルと影の色もはっきりと表示されます。
  • 有効+可視+活性+操作可能: 「有効+可視+活性」状態と外観は同じですが、フォーカス移動が可能です。
  • 有効+可視+活性+操作可能+フォーカス: ボタンのベベル領域の枠の色が強調されると同時にフォーカスの枠がベベル領域の内側に表示されます。
[Note] テキストボタンコントロールの構成要素
  • 影領域(非押下時: 右辺と下辺、押下時: 左辺と上辺)
  • ベベル領域(ライトカラー、ベースカラー、ダークカラーの 3 種類の色で構成される矩形領域)
  • フォーカス状態の時に表示される枠(フォーカス枠)
  • テキストラベル

詳細情報: SFYButtonControl | SFZTextButtonControl | SFXBevelColor

[Note] フォーカス状態フラグについて

SFYResponder::SetState 関数を呼び出す直前、 レスポンダの可視、活性、操作可能、フォーカスのすべての状態のフラグ値が true であったとします (このレスポンダがフォーカスを持っていたとします)。

この場合、 visible、active、または enable 引数のうち 1 つ以上の引数に false を指定して SFYResponder::SetState 関数を呼び出せば、 focus 引数に true を指定していても、 このレスポンダのフォーカス状態フラグの値は強制的に false に設定されます。

そして、もし存在すれば、1 つだけ背面にある操作可能な姉妹レスポンダ (存在しない場合は、1 つだけ前面にある操作可能な姉妹レスポンダ) のフォーカス状態フラグが false から true に変更されます (フォーカスはその姉妹レスポンダに移動します)。

※1. フォーカス状態のフラグ値を true に設定するには、 visible / active / enable / focus のすべての引数に true を指定して SFYResponder::SetState 関数を呼び出す必要があります。 このとき、 フォーカス状態のフラグが true である姉妹レスポンダが存在した場合、 そのフラグは 強制的に false に変更されます (その姉妹レスポンダはフォーカスされない状態になります)。

※2. 操作可能なレスポンダとは、 可視、活性、操作可能の状態フラグの値が true であるレスポンダのことです。

※3. 可視、活性、操作可能の状態フラグは、 SFYResponder::SetState 関数の対応する各引数に指定した値が無条件にそのまま設定されます。

例 9.14. 状態の設定

Void USRResponder::SetState(Void)
{
    // 可視、活性、操作可能、フォーカスの各状態のフラグを true に設定し、
    // このレスポンダのフォーカス状態を ON にする
    SetState(true, true, true, true);
    // ※ 親レスポンダのフォーカス状態は ON であると仮定

    // 可視状態のフラグを false に設定する(このレスポンダを不可視状態 OFF にする)
    SetStateVisible(false);
    // ※ このとき、活性状態と操作可能状態のフラグ値は true のままだが、
    //    フォーカス状態フラグ値は自動的に true から false に変更されることに注意!
    //    そして、もし存在すれば、1 つだけ背面にある操作可能な姉妹レスポンダ(存在しない場合は、1 つだけ前面にある操作可能な姉妹レスポンダ)の
    //    フォーカス状態フラグが false から true に変更される(その姉妹レスポンダにフォーカスが移動する)

    // 可視状態のフラグを true に設定すると、操作可能状態 ON になるが、
    // フォーカス状態フラグ値は false のままなので、フォーカス状態は OFF
    SetStateVisible(true);

    // フォーカス状態を ON にするには、フォーカス状態フラグを true に設定する必要がある
    SetStateFocus(true);

    return;
}

レスポンダが状態フラグに設定されているように実際に振舞う場合、 レスポンダの状態は ON、 そうでない場合は OFF であると呼ぶことにします。

可視、活性、または操作可能の状態フラグが true に設定されていたとしても、 レスポンダはそのように振舞うとは限りません。 しかし、 フォーカスの状態フラグの値は、 フォーカス状態が ON である(フォーカスされている)ときに限り true です。 逆に言えば、 フォーカス状態が OFF である(フォーカスされていない)ときは false です。

[Tip]

可視状態フラグの値が true であったとしても、 レスポンダが描画されなければ、可視状態は OFF です。 逆に、実際に描画されるならば、可視状態は ON です。

レスポンダの状態が ON であるか否かは、 以下のように再帰的に決定できます(3 つの条件がすべて成立すれば、状態は ON です)。

  1. 状態フラグが true に設定されている
  2. (もし存在すれば)1 つ優先順位の高い状態が ON である
  3. (もし存在すれば)親レスポンダの同じ状態が ON である
[Note] 状態の優先順位

有効、可視、活性、操作可能、フォーカスの順で各状態に優先順位が付けれています。

[Tip] Tip

SFYResponder::GetStateVisible / SFYResponder::GetStateActive / SFYResponder::GetStateEnable / SFYResponder::GetStateFocus 関数では、 inherit 引数の指定により、状態のフラグ値、またはON / OFF 値を取得できます。

[Note] 状態の ON / OFF 値
  1. いま画面上にウィンドウが描画されているとすれば、 ウィンドウの可視状態フラグは true、可視状態は ON です。

    ウィンドウ内にボタンも描画されていれば、 ボタンの可視状態フラグも true、可視状態も ON です。 ボタンの可視状態も ON です。

    ここで、 ウィンドウの可視状態フラグを false にすると、 ウィンドウの可視状態は自動的に OFF になり、 ウィンドウは描画されなくなります。

    子であるボタンの可視状態も自動的に OFF になり、 ボタンも描画されなくなります。 このとき、ボタンの可視状態フラグは true のままです。

  2. いま画面上にボタンがフォーカスされているとすれば、 ボタンのフォーカス状態と可視状態は共に ON です。

    フォーカス状態よりも優先順位の高い可視状態フラグを false に設定すると、 フォーカス状態は自動的に OFF になり、 ボタンはフォーカスされなくなります。 このとき、 活性状態と操作可能状態のフラグ値は true のままですが、 フォーカス状態フラグだけは false になる仕様に注意が必要です (再びフォーカス状態を ON にするには、フォーカス状態フラグを true に設定する必要があります)。

[Note] 状態イベントの処理

レスポンダは、状態の ON / OFF が切り替わると、 状態イベントを受信します。

このイベントについて 状態イベント専用ハンドラを登録することが可能です。

参照: SFYResponder::Initialize | SFYResponder::Terminate | SFYResponder::SetState | SFYResponder::SetStateVisible | SFYResponder::SetStateActive | SFYResponder::SetStateEnable | SFYResponder::SetStateFocus

9.2.15. イベント

イベント(SFXEvent)は、 イベントタイプと 2 つのパラメータ(P16 パラメータと P32 パラメータ)から構成されます。

イベントを処理するハンドラは、 SFYResponder::RegisterHandler / SFYDistributer::RegisterHandler 関数を使用してレスポンダ、または ルートSFZRoot)に設定された SFYDistributer インスタンスに登録します。

イベントには、以下の 3 種類があります。

  1. BREW SDK で定義される BREW イベント
  2. SophiaFramework UNIVERSE 独自のレスポンダイベント
  3. 開発者独自のユーザーイベント

BREW イベントのイベントタイプ名は、BREW SDK で定義されるイベントタイプ名の先頭に SF 接頭語が付加された名前になります。

たとえば、SFEVT_KEY イベント(キーイベント[SFEVT_KEY])は BREW イベントです。

一方、レスポンダイベントのイベントタイプ名は、 SFEVT_RESPONDER_ 接頭語が付加された名前になります。

たとえば、SFEVT_RESPONDER_RENDER イベント(描画イベント)は レスポンダイベントです。

また、イベントの配信方法からイベントは配信型イベントと、 コールバック型イベントの 2 種類に分類されます。

配信型イベントは SFYResponder::Distribute 関数を使用してレスポンダに配信します (このとき、トレーサの配信規則が参照されます)。 イベントを受信したレスポンダは対応するハンドラを呼び出します。 BREW イベントは配信型イベントです。

コールバック型イベントは SFYResponder::InvokeForward / SFYResponder::InvokeBackward 関数を使用してレスポンダに送信します。 イベントを受信したレスポンダは対応するハンドラを呼び出します。 レスポンダイベントはコールバック型イベントです。

[Caution] ユーザーイベント

ユーザーイベントとは、 SFEVT_USER_CLASS_BEGIN(0x8000) から SFEVT_USER_CLASS_END(0xFFFE) の範囲でユーザーが自由に定義できるユーザー独自のイベントです。

ユーザーイベントを配信型イベントとして配信するには、 配信規則をトレーサに登録する必要があります。

参照: イベント処理 | イベント一覧

9.2.16. イベントループ

イベントループとは、 BREW 環境から受信した BREW イベントトレーサの配信規則に従い、 ルートSFZRoot)を起点としてレスポンダツリー上の各レスポンダに配信し、 ハンドラを駆動するイベントドリブンな工程の繰り返しのことです。

参照: イベント処理

9.2.17. 配信エンジン

配信エンジン(SFYDistributer)とは、 配信型イベントトレーサの配信規則に基づいて レスポンダツリーに配信するアルゴリズムです。

イベントをレスポンダツリーに配信するには、 ルートレスポンダに配信エンジンを関連付ける必要があります。

[Note] SFYApplication クラスが内部で保持するルート

SFYApplication::SFYApplication コンストラクタの処理により、 配信エンジン(SFYDistributer)は SFYApplication クラスが内部で保持する ルートに関連付けられます。

SFY アプリでは、 このルートをレスポンダツリーのルートレスポンダとして使用します。

※ 配信エンジンは、 SFYResponder::SetDistributer 関数を使用して設定します。

参照: SFYApplication::SFYApplication コンストラクタの内部実装

[Note] 注意

イベント処理の詳細については、 イベント処理を参照してください。

9.2.18. 描画エンジン

描画エンジン(SFYRenderer)とは、 レスポンダツリーレスポンダ空間に描画するためのアルゴリズムです。

レスポンダツリーを描画するには、 ルートレスポンダに描画エンジンを関連付ける必要があります。

[Note] SFYApplication クラスが内部で保持するルート

SFYApplication::SFYApplication コンストラクタの処理により、 描画エンジン(SFYRenderer)は SFYApplication クラスが内部で保持する ルートに関連付けられます。

SFY アプリでは、 このルートをレスポンダツリーのルートレスポンダとして使用します。

※ 描画エンジンは、 SFYResponder::SetRenderer 関数を使用して設定します。

参照: SFYApplication::SFYApplication コンストラクタの内部実装

[Note] 注意

描画処理の詳細については、 描画処理を参照してください。

9.2.19. トレーサ

トレーサは、 配信型イベントを配信する規則のことで、 SFYTracer クラスが管理します。

トレーサの配信規則は、 SFYResponder::RegisterTracer / SFYDistributer::RegisterTracer 関数を使用してイベントと関連付けてレスポンダ、または SFYApplication が内部に保持するルートSFZRoot)に設定された SFYDistributer インスタンスに登録します。

SFYDistributer インスタンスには、 デフォルトの配信規則として標準トレーサが設定されています。

ルートは SFYDistributer インスタンスのトレーサ (デフォルトでは標準トレーサ)の設定を継承し、 子レスポンダは親レスポンダのトレーサの設定を継承します。

[Note] SFYDistributer インスタンスの取得

SFYApplication が内部に保持するルートに設定された SFYDistributer のインスタンスを取得するには、 SFYApplication::GetDistributer 関数を呼び出します。

トレーサの内容を変更しなかった場合は、 標準トレーサの配信規則によりイベントは配信されます。

[Note] トレーサのカスタマイズ

一般的なアプリ開発では、 標準トレーサの設定で十分であり、 トレーサに新たな配信規則を設定する必要はほとんどありません。

配信規則には、 以下の 3 つの要素があります。

  1. 配信条件. イベントを配信するレスポンダの 状態を指定します。

  2. 処理順序.ハンドラを呼び出す順序を指定します。

  3. 重複条件.イベントを重複して処理するかどうかを指定します。

同一のイベントに対して複数の配信規則をトレーサに登録した場合、 最後に登録した配信規則だけが有効になります (それ以前の配信規則は無効になります)。

[Caution] トレーサに設定可能なイベントの種類

トレーサの設定は、配信型イベントについて行います。 コールバック型イベントの配信規則はトレーサに登録してはいけません。

[Tip] 配信型イベント

配信型イベントとは、 SFYResponder::Distribute 関数を使用して配信するイベントです。 このイベントはトレーサの配信規則に基づいて配信され、 配信規則の設定により配信先レスポンダの子孫レスポンダにもイベントを配信できます。 BREW イベントは配信型イベントです。

[Tip] コールバック型イベント

コールバック型イベントとは、 SFYResponder::InvokeForward / SFYResponder::InvokeBackward 関数を使用して送信するイベントです。 このイベントは送信先のレスポンダにだけ送信されます。送信先レスポンダの子孫レスポンダには送信されません。 レスポンダイベントはコールバック型イベントです。

参照: 標準トレーサ | イベント

例 9.15. トレーサへの配信規則の登録

SFCError USRResponder::MakeTracer(Void)
{

    // AVK_SOFT1 から AVK_SOFT4 までのキーイベントについて
    // 『処理順序:前面から背面、配信条件:有効状態 ON、重複条件:なし』
    // という配信規則をトレーサに登録する
    return RegisterTracer(
        SFXEventRange(SFEVT_KEY, SFEVT_KEY, AVK_SOFT1, AVK_SOFT4),
        SFYTracer::ORDER_FORWARD, SFYTracer::STATE_ALL, false
    );
}

9.2.20. ハンドラ

ハンドラとは、 イベントを処理する関数のことです。

ハンドラは、SFYResponder::RegisterHandler / SFYDistributer::RegisterHandler 関数を使用してイベントと関連付けてレスポンダ、または SFYApplication が内部に保持するルートSFZRoot)に設定された SFYDistributer インスタンスに登録します。

同一のイベントに対して複数のハンドラを登録することが可能です。 ハンドラは登録順、または登録の逆順に呼び出します。

ハンドラがイベントを処理したとき、 そこで終了するか、 あるいは、無くなるまでハンドラの呼び出しを継続するかの設定が可能です。

例 9.16. ハンドラの登録

SFCError error;

1 つのハンドラを登録する
error = RegisterHandler(SFXEventRange(SFEVT_KEY, SFEVT_KEY, SFP16_BEGIN, SFP16_END), 
                        XANDLER_INTERNAL(OnKey)
        );


複数のハンドラをまとめて登録する
static SFXEventRange::AtomRecConst range[] = {
    {             SFEVT_KEY,              SFEVT_KEY,          SFP16_BEGIN,            SFP16_END},
    {       SFEVT_KEY_PRESS,        SFEVT_KEY_PRESS,          SFP16_BEGIN,            SFP16_END},
    {     SFEVT_KEY_RELEASE,      SFEVT_KEY_RELEASE,          SFP16_BEGIN,            SFP16_END}
};
SFYHandler::RuleRec rule[lengthof(range)];

rule[0].spp = XANDLER_FUNCTION(OnKey);
rule[0].reference = this;
rule[1].spp = XANDLER_FUNCTION(OnKeyPress);
rule[1].reference = this;
rule[2].spp = XANDLER_FUNCTION(OnKeyRelease);
rule[2].reference = this;

error = RegisterHandler(atomic_cast(range), rule, lengthof(range));

9.2.21. トレーサリスト

トレーサリストとは、 SFYTracer クラスが管理する、 スタック型(先頭が最前面、底が最背面)のトレーサの配信規則のリストのことです。

新たに配信規則をレスポンダまたは SFYDistributer インスタンスに登録すると、 配信規則はトレーサリストの先頭にプッシュダウンされます。 一方、条件で指定された配信条件をレスポンダまたは SFYDistributer インスタンスから登録解除するときは、 先頭から検索して条件に一致する配信規則がトレーサリストの先頭から 1 つポップアップされます。

同一イベントに複数個の配信規則が登録されていた場合、 最後に登録された配信規則だけが有効になります。 それ以前の旧い配信規則は無効になります。

[Note] 注意
レスポンダまたは SFYDistributer インスタンスに付き 1 つのトレーサリストが存在します。

9.2.22. ハンドラリスト

ハンドラリストとは、 SFYHandler クラスが管理する、 スタック型(先頭が最前面、底が最背面)のハンドラ(ハンドラ関数)のリストのことです。

新たなハンドラをレスポンダまたは SFYDistributer インスタンスに登録すると、 そのハンドラはハンドラリストの先頭にプッシュダウンされます。

条件で指定されたハンドラをレスポンダ、 または SFYDistributer インスタンスから登録解除すると、 先頭から検索して条件に一致するハンドラがハンドラリストの先頭から 1 つポップアップされます。

同一イベントに複数個のハンドラが登録されていた場合、 ハンドラリストを辿る方法には、 先頭(最前面)から末尾(最背面)と、 末尾(最背面)から先頭(最前面)の 2 通りがあります。

[Note] 注意
レスポンダまたは SFYDistributer インスタンスに付き 1 つのハンドラリストが存在します。

9.2.23. 配信型

配信型とは、 SFYResponder::Distribute 関数を使用してイベントをレスポンダに配信し、 ハンドラを呼び出す方法のことです。

具体的には、 SFYResponder::Distribute 関数を呼び出して配信エンジンを起動します。 配信エンジンはトレーサに登録された配信規則に基づいて イベントレスポンダツリー上のレスポンダに配信します。 イベントを受信したレスポンダは対応するハンドラを呼び出します。

[Note] BREW イベントの配信

BREW イベントは配信型です。

[Note] 子孫レスポンダへの配信

コールバック型イベントと異なり、 配信型イベントはトレーサの配信規則の設定により配信先レスポンダの子孫レスポンダに配信することが可能です。

なお、配信型イベントの配信対象は SFYResponder::Distribute 関数を呼び出した時点で構成されているレスポンダツリー上のレスポンダです。 このイベントを処理している時に動的に新規生成されたレスポンダには配信されません。 また、イベント処理中に SFYResponder::Terminate 関数により破棄されたレスポンダにも配信されません。

9.2.24. コールバック型

コールバック型とは、 SFYResponder::InvokeForward / SFYResponder::InvokeBackward 関数を使用してイベントを送信し、 ハンドラを呼び出す方法のことです。

ハンドラリスト内のハンドラを最前面から呼び出す(ハンドラ登録の逆順に呼び出す)場合は SFYResponder::InvokeForward 関数、 最背面から呼び出す(ハンドラ登録の順に呼び出す)場合は SFYResponder::InvokeBackward 関数を利用します。

SFYResponder::InvokeForward / SFYResponder::InvokeBackward 関数にはイベントを重複して処理するかどうかを表す引数があります。

[Note] レスポンダイベントの送信

レスポンダイベントはコールバック型です。

[Note] 子孫レスポンダへの送信

配信型イベントと異なり、 コールバック型イベントは送信先レスポンダ内だけで処理されます。 このイベントは子孫レスポンダに送信されません。

[Caution] デストラクタ内でのイベント送信

デストラクタを実行する前に自レスポンダの有効状態は無効になっているため、 デストラクタ内で自レスポンダにイベントを送信してはいけません(送信した場合の動作は未定義です)。

9.2.25. タイプ

タイプとは、 レスポンダのクラス識別子として自由に設定できる 4 文字リテラル(four_char_code マクロで定義)のことです。

タイプは SFYResponder::SetType 関数を使用して設定します。 タイプを設定しなかった場合は、親クラスのタイプを継承します。

SFYResponder::GetType 関数を呼び出してレスポンダのタイプの値を参照することにより、 抽象クラスのポインタに格納されたレスポンダの具象クラスを特定できます。

[Caution] 注意事項

タイプはレスポンダのクラスを定義するときにコンストラクタ内で設定します。

小文字アルファベットまたは記号からなる 4 文字リテラルは SophiaFramework UNIVERSE で予約されています(タイプ一覧)。 アプリ開発用には、大文字アルファベット 4 文字からなる 4 文字リテラルを利用してください。

例 9.17. タイプの設定

USRResponder::USRResponder(Void) static_throws
{
    if (static_try()) {

        // タイプは必ずこの場所で設定する
        // このようにすると親クラスのコンストラクタ内でエラーが発生した場合は
        // 親クラスのタイプが保持され、自クラスのコンストラクタ内でエラーが
        // 発生した場合は自クラスのタイプが設定されるようになる
        // 外部からこのクラスを利用する場合にエラーの発生個所を特定しやすくなる
        SetType(four_char_code('U', 'R', 'S', 'P'));

        // その他の初期化処理を記述する

        // ...(省略)...
    }
}

例 9.18. タイプの利用

Void USRResponder::PrintType(SFYResponderSmpConstRef param) const
{
    switch (param->GetType()) {

        case SFZWindow::CODE_TYPE:

            TRACE("It is a SFZWindow class.");
            break;

        case SFZDialog::CODE_TYPE:

            TRACE("It is a SFZDialog class.");
            break;

        case SFZTextButtonControl::CODE_TYPE:

            TRACE("It is a SFZTextButtonControl class.");
            break;

        default:

            TRACE("It is an unknown class.");
            break;
    }

    return;
}

9.2.26. ID

ID とは、 レスポンダのインスタンス識別子として自由に設定できる 32ビット符号なし整数(UInt32 型)のことです。

SFYResponder クラスには、SFYResponder::GetChildFront 関数など ID を利用してレスポンダのインスタンスを検索する関数が用意されています。

ID は SFYResponder::SetID 関数を使用して設定します(デフォルト値: 0)。

[Tip] Tip
異なるレスポンダに同一の ID を設定できます。 ID は変更可能です。

例 9.19. ID の設定

SFCError USRResponder::MakeButton(Void)
{
    SFZTextButtonControlSmp button;
    SFCError error(SFERR_NO_ERROR);

    if ((button = SFZTextButtonControl::NewInstance(&error)) != null) {

        if ((error = button->SetParent(GetThis())) == SFERR_NO_ERROR) {

            // テキストボタンコントロールの ID を 100 に設定する
            button->SetID(100);

            // ...(省略)...
        }
    }

    return error;
}

例 9.20. ID を用いた検索

SFZTextButtonControlSmp USRResponder::GetButton(Void) const
{
    // ID を利用すればクラス変数を用いてレスポンダを管理しなくてもよい

    // ID が 100 であるテキストボタンコントロールを取得する
    return static_pointer_cast<SFZTextButtonControl>(GetChildFront(100));
}

9.2.27. リファレンス

リファレンスとは、 レスポンダのインスタンス識別子として自由に設定できる 4 バイト値(VoidPtr 型)のことです。

SFYResponder::SetReference 関数を使用して、 任意の 4 バイト値を設定できます(デフォルト値: null)。

例 9.21. テキストボタンコントロールへの識別番号の設定とその参照

SFZTextButtonControlSmp _button;
SInt32 i;

// 10 個のテキストボタンコントロールを作成し番号(リファレンス値)を設定する
for (i = 0; i < 10; ++i) {

    // テキストボタンコントロールを作成する
    if ((_button = SFZTextButtonControl::NewInstance(&error)) != null) {

        // テキストボタンコントロールの親 GetThis() に設定する
        error = _button->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            // テキストボタンコントロール識別用番号を設定する
            _button->SetReference(reinterpret_cast<VoidPtr>(i));
        }
    }
}

// ...(省略)...

// テキストボタンコントロール識別用番号を取得する
SInt32 number = reinterpret_cast<SInt32>(_button->GetReference());

9.2.28. アタッチメントフレームとコンテントレスポンダ

SFYResponder::SetFrame 関数を使用して、 レスポンダにフレームを装着することが可能です。 このとき、 レスポンダに装着したフレームアタッチメントフレーム、 フレームが装着されたレスポンダをコンテントレスポンダと呼びます。

レスポンダがアタッチメントフレームまたはコンテントレスポンダであるかの判定は、 それぞれ SFYResponder::IsFrame または SFYResponder::HasFrame 関数を使用して行います。

SFYFrame を継承するクラスのインスタンス(フレーム)がアタッチメントフレームの対象となります。

一方、コンテントレスポンダの対象となるレスポンダは、以下の 3 種類です。

  1. SFZWindow を継承するウィンドウ
  2. SFZDialog を継承するダイアログ
  3. SFYMenu を継承するメニュー

図 9.16. アタッチメントフレームとコンテントレスポンダ


アタッチメントフレームとコンテントレスポンダ

アタッチメントフレームとコンテントレスポンダの主な特徴は以下の通りです。

  1. 描画エンジンの観点では、 アタッチメントフレームはコンテントレスポンダの 1 つ下の妹レスポンダとして振舞います。
  2. 状態配信エンジンの観点では、 アタッチメントフレームはコンテントレスポンダの子レスポンダとして振舞います。
  3. アタッチメントフレームの実領域は、 コンテントレスポンダの実領域を外枠やタイトルを描画するためのフレーム余白領域だけ拡大した領域になるように自動的に管理されます。
  4. コンテントレスポンダに対して実領域設定・移動・状態変更・終了などの処理を行うと、 アタッチメントフレームでもそれに伴う処理が自動的に行われます。 このとき、アタッチメントフレームを操作する必要はないのでアタッチメントフレームは透過的に扱えます。
[Note] 注意
実際にフレームを利用する方法に関しては、 こちらを参照してください。

■アタッチメントフレームとコンテントレスポンダの実領域

SFYResponder::SetRealBound 関数を使用して、 コンテントレスポンダの実領域を設定すると、 内部処理により自動的にその実領域をフレーム余白領域だけ拡大した領域がアタッチメントフレームの実領域として設定されます。 この処理は、SFYResponder::SetFrame 関数の内部でも行われます。

逆に、 SFYResponder::SetRealBound 関数を使用して、 アタッチメントフレームの実領域を設定すると、 内部処理により自動的にその実領域をフレーム余白領域だけ縮小した領域がコンテントレスポンダの実領域として設定されます。

[Note] フレーム余白領域

フレーム余白領域とは、 SFYResponder::GetSuitableMargin 関数を呼び出すことで得られる、 外枠やタイトルを描画するための領域です。 SFYResponder::GetSuitableMargin 関数は、 SFYFrame を継承するクラスのインスタンス(フレーム)についてのみ有効です。

フレーム余白領域の計算は内部で自動的に行われるので、 開発者がこの関数を利用する機会はほとんどないでしょう。

■レスポンダツリーにおけるアタッチメントフレーム

SFYResponder::SetParent 関数を呼び出して、 明示的にアタッチメントフレームの親レスポンダを設定することはできません。

SFYResponder::SetFrame 関数を使用してレスポンダに装着した、 アタッチメントフレームのレスポンダツリーにおける扱いは、 以下の点で他のレスポンダと異なることに注意する必要があります。

SFYResponder::GetParent 関数を呼び出して得られるアタッチメントフレームの親レスポンダは、 コンテントレスポンダと同じです。 アタッチメントフレームは、常にコンテントレスポンダの 1 つ下の妹レスポンダであるように内部で管理されます。 また、アタッチメントフレームの実領域は、 コンテントレスポンダの実領域をフレーム用余白領域だけ拡大した領域です。 結果的に、アタッチメントフレームはコンテントレスポンダの外枠として描画されます。

一方、 状態配信エンジンの観点では、 アタッチメントフレームはコンテントレスポンダの子レスポンダとして振舞います。

つまり、アタッチメントフレームはコンテントレスポンダの状態を継承します。 例えば、 コンテントレスポンダの可視状態を ON から OFF に変更すると、 アタッチメントフレームの可視状態もそれに連動して ON から OFF に変わります。

[Caution] アタッチメントフレームの状態フラグについて

アタッチメントフレームの状態フラグは、すべて true に設定する必要があります。

コンテントレスポンダが受信したイベントは、 アタッチメントフレームがコンテントレスポンダの 1 番目の子レスポンダであるものとしてトレーサに登録された規則を利用して配信されます。

[Caution] 注意

アタッチメントフレームとコンテントレスポンダには本当の親子関係や姉妹関係が存在しないので、 この 2 者については親子イベント[SFEVT_RESPONDER_OWNER]は発生しません。

■アタッチメントフレームの透過性

アタッチメントフレームは、以下のように透過的に扱われます。

コンテントレスポンダの実領域を設定すると、 内部処理により自動的にその実領域をフレーム余白領域だけ拡大した領域がアタッチメントフレームの実領域として設定されます。

SFYResponder::GetChildFront などの関数でアタッチメントフレームを取得しようとしても、 アタッチメントフレームは取得できません。 また、SFYResponder::GetChildCount 関数で子レスポンダをカウントしてもアタッチメントフレームはその数に含まれません。

SFYResponder::ToFront などの関数を呼び出して姉妹レスポンダ間でのアタッチメントフレームの位置を変えようとしても、 何も起こりません。コンテントレスポンダもアタッチメントフレームも移動せず、そのままです。

逆に、 姉妹レスポンダ間におけるコンテントレスポンダの位置を変えようとしてそれを呼び出した場合、 コンテントレスポンダと共にアタッチメントフレームも一緒に移動します。 アタッチメントフレームは、常にコンテントレスポンダの 1 つ下の妹レスポンダであるように内部で管理されます。

SFYResponder::Terminate 関数を呼び出してコンテントレスポンダを終了すると、 アタッチメントフレームは自動的にコンテントレスポンダから切り離されて見えなくなり、 他のレスポンダに装着可能な通常のフレームに戻ります。

アタッチメントフレームを終了した場合は、 アタッチメントフレームがコンテントレスポンダから切り離され、見えなくなるだけです。 コンテントレスポンダには何の影響も及ぼしません。