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

9.14. ウィンドウ(応用編)

ウィンドウ内部の描画や仮想領域の扱い方などについて解説します。

9.14.1. ウィンドウ内部に描画する( 1 )

図 9.34. 動作例

動作例

ウィンドウ(SFZWindow)の上にコントロールやコンテナを配置する以外に、 ウィンドウ内部にテキストやイメージを描画できます。

ウィンドウ(SFZWindow)を外部から描画を行うには、 ウィンドウ(SFZWindow)に描画ハンドラを登録します。

例 9.62. 宣言

SFMTYPEDEFCLASS(USRApplication)
class USRApplication: public SFYApplication {
    SFMSEALCOPY(USRApplication)
private:
    SFZWindowSmp _window;

    // ...(省略)...
private:
    SFCError Make(Void);

    // ウィンドウ用の描画ハンドラ
    XANDLER_DECLARE_VOIDRENDER(OnRenderRequest)
};

例 9.63. 実装

SFCError USRApplication::Make(Void)
{
    SFCError error(SFERR_NO_ERROR);

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

        // ウィンドウの親レスポンダを USRApplication に設定する
        error = _window->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            // ウィンドウに描画ハンドラを登録する
            error = _window->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RENDER, SFEVT_RESPONDER_RENDER, SFP16_RENDER_REQUEST, SFP16_RENDER_REQUEST),
                XANDLER_INTERNAL(OnRenderRequest)
            );
            if (error == SFERR_NO_ERROR) {

                // ウィンドウの実領域を設定する
                // ※ルートのローカル領域を (10, 10) だけ Deflate した領域に設定する
                _window->SetRealBound(GetLocalBound().Deflate(10, 10));

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

                // ウィンドウを最前面に移動する
                _window->ToFront();
            }
        }
    }

    return error;
}

// ウィンドウの描画ハンドラ
XANDLER_IMPLEMENT_VOIDRENDER(USRApplication, OnRenderRequest, invoker, reason, graphics)
{
    SFXRectangle local;
    SInt16 i;
    SInt16 j;

    local.Set(_window->GetLocalBound());

    // チェック模様を描画する
    for (j = 0; j < local.GetBottom(); j += 10) {

        for (i = 0; i < local.GetRight(); i += 10) {

            if ((i + j) / 10 % 2 == 0) {

                graphics->FillRectangle(SFXRectangle(i, j, 10, 10), SFXRGBColor(0xCC, 0xFF, 0xCC, 0x00));
            }
            else {

                graphics->FillRectangle(SFXRectangle(i, j, 10, 10), SFXRGBColor(0xAA, 0xDD, 0xAA, 0x00));
            }
        }
    }

    return;
}

9.14.2. ウィンドウ内部に描画する( 2 )

図 9.35. 動作例

動作例

ウィンドウの上にコントロールやコンテナを配置する以外に、 ウィンドウ内部にテキストやイメージを描画できます。

ユーザー定義ウィンドウで描画を行うには、 SFYWidget::HandleRenderRequest 仮想関数をオーバーライドします。 この場合、描画ハンドラの登録を省略できます。

[Note] HandleRenderRequest 仮想関数をオーバーライドするメリット

SFYWidget::HandleRenderRequest 仮想関数は、 (SFEVT_RESPONDER_RENDER, SFP16_RENDER_REQUEST) 描画イベントが発生したときに最初に呼び出される SFYWidget に登録された描画ハンドラの中から呼び出されます。

描画ハンドラを登録してウィンドウを描画することも可能ですが、 SFYWidget::HandleRenderRequest 仮想関数をオーバーライドする方法では描画ハンドラを登録する手間を省略できます。

例 9.64. 宣言

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow: public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)

    // ...(省略)...
protected:

    // 描画イベントを受信すると呼び出される HandleRenderRequest 仮想関数をオーバーライドする
    virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const;
};

例 9.65. 実装

// ウィンドウの描画ハンドラ
Void USRWindow::HandleRenderRequest(SFXGraphicsPtr graphics) const
{
    SFXRectangle local;
    SInt16 i;
    SInt16 j;

    local.Set(GetLocalBound());

    // チェック模様を描画する
    for (j = 0; j < local.GetBottom(); j += 10) {

        for (i = 0; i < local.GetRight(); i += 10) {

            if ((i + j) / 10 % 2 == 0) {

                graphics->FillRectangle(SFXRectangle(i, j, 10, 10), SFXRGBColor(0xCC, 0xFF, 0xCC, 0x00));
            }
            else {

                graphics->FillRectangle(SFXRectangle(i, j, 10, 10), SFXRGBColor(0xAA, 0xDD, 0xAA, 0x00));
            }
        }
    }

    return;
}

9.14.3. ウィンドウの仮想領域のスクロール

もしウィンドウの仮想領域が実領域よりも大きな領域に設定されているならば、 仮想領域を上下にスクロールできます。

図 9.36. 動作例(左:スクロール前、右:スクロール後)

動作例(左:スクロール前、右:スクロール後)

以下は、汎用ウィンドウ(SFZWindow)の仮想領域を上下にスクロールするコードの例です。

例 9.66. 宣言

SFMTYPEDEFCLASS(USRApplication)
class USRApplication: public SFYApplication {
    SFMSEALCOPY(USRApplication)
private:
    SFZWindowSmp _window;

    // ...(省略)...
private:
    SFCError Make(Void);
    XANDLER_DECLARE_VOIDRENDER(OnRenderRequest)
};

例 9.67. 実装

SFCError USRApplication::Make(Void)
{
    SFCError error(SFERR_NO_ERROR);

    if ((_window = SFZWindow::NewInstance(&error)) != null) {

        error = _window->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
 
            error = _window->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RENDER, SFEVT_RESPONDER_RENDER, SFP16_RENDER_REQUEST, SFP16_RENDER_REQUEST),
                XANDLER_INTERNAL(OnRenderRequest)
            );
            if (error == SFERR_NO_ERROR) {

                _window->SetRealBound(GetLocalBound().Deflate(10, 10));

                // 仮想領域を下に 100 ピクセルだけ拡張して設定する
                _window->SetVirtualBound(SFXRectangle(_window->GetVirtualBound()).AddBottom(100));

                // スクロール移動量(単位:ピクセル)を設定する
                _window->SetScrollStep(5);

                // 下端または上端に到達したときに次のスクロールで上端または下端に移動するかどうかを設定する
                _window->SetScrollRepeat(true);

                _window->SetState(true, true, true, true);

                _window->ToFront();
            }
        }
    }

    return error;
}

XANDLER_IMPLEMENT_VOIDRENDER(USRApplication, OnRenderRequest, invoker, reason, graphics)
{
    SFXRectangle local;
    SInt16 i;
    SInt16 j;

    local.Set(_window->GetLocalBound());

    for (j = 0; j < local.GetBottom(); j += 10) {

        for (i = 0; i < local.GetRight(); i += 10) {

            if ((i + j) / 10 % 2 == 0) {

                graphics->FillRectangle(SFXRectangle(i, j, 10, 10), SFXRGBColor(0xCC, 0xFF - j, 0xCC + j, 0x00));
            }
            else {

                graphics->FillRectangle(SFXRectangle(i, j, 10, 10), SFXRGBColor(0xAA, 0xDD - j, 0xAA + j, 0x00));
            }
        }
    }

    return;
}
[Note] 注意
ユーザー定義ウィンドウを用いる場合でも、 上記方法とほとんど同じ方法で実現できます。