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

3.8. コンテナ

3.8.1. 汎用コンテナとスクロールバーコントロール

下図の汎用コンテナ(SFZContainer)を作成します。

図 3.30. 汎用コンテナ

汎用コンテナ

コードの概要は以下の通りです。

  1. ウィンドウ(SFZWindow クラスを継承する ItsWindow)を作成します。
  2. 汎用コンテナ(SFZContainer)をウィンドウ内に配置します。
  3. テキストボタン(SFZTextButtonControl)を汎用コンテナ内に配置します。
  4. スクロールバーコントロール(SFZContainerScrollBarControl)を汎用コンテナの右隣に配置します。
[Note] コンテナ

コンテナは、コントロールや他のコンテナ(コンテナ・ウィンドウ・ダイアログ)を配置するように設計されたレスポンダです。

ウィンドウやダイアログもコンテナの一種です。

コンテナのなかにコントロールやコンテナなどのレスポンダが配置されている場合、 SFYContainer::SetScrollDownKey / SFYContainer::SetScrollUpKey / SFYContainer::SetPageDownKey / SFYContainer::SetPageUpKey / SFYContainer::SetSnapDownKey / SFYContainer::SetSnapUpKey 関数で設定するスクロールキーを使用してレスポンダ間でフォーカスを移動できます。

仮想領域実領域よりも大きい場合は、 フォーカス移動機能と連動した、 仮想領域の上下方向へのスクロール機能も利用できます。

ItsWindow を定義します。

例 3.51. ItsWindow クラスの定義

// ItsWindow クラスの定義
SFMTYPEDEFRESPONDER(ItsWindow)  //  便利な型を生成するマクロ
class ItsWindow : public SFZWindow
{
    SFMSEALRESPONDER(ItsWindow)  // インスタンスのコピーを禁止するマクロ

    // SFYResponder からこのクラスに至るまでの継承順序を指定するマクロ
    SFMRESPONDERINSTANTIATEFOUR(ItsWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
public:

    // 小文字アルファベットまたは記号 4 文字からなるタイプは予約されているので
    // ItsWindow のタイプを大文字アルファベット('I', 'W', 'N', 'D')で定義する
    enum CodeEnum {
        CODE_TYPE = four_char_code('I', 'W', 'N', 'D')
    };
    SFMTYPEDEFTYPE(CodeEnum)

public:
    static ItsWindowSmp NewInstance(SFCErrorPtr exception = null);

    // ItsWindow 上の各種コンテナおよびコントロールを作成する関数
    SFCError Make(Void);

protected:
    explicit ItsWindow(Void) static_throws;
    virtual ~ItsWindow(Void);

private:

    // キーハンドラ
    XANDLER_DECLARE_BOOLEVENT(OnKey)
};

// 配色定義
#define COLOR_ITS_WINDOW_BACK (SFXRGBColor(0xCC, 0xFF, 0xCC, 0x00))

// コンストラクタ
ItsWindow::ItsWindow(Void) static_throws
{
    if (static_try()) {
        SetType(CODE_TYPE);

        // ItsWindow のキーハンドラを登録する
        static_throw(RegisterHandler(
            SFXEventRange(SFEVT_KEY, SFEVT_KEY, SFP16_BEGIN, SFP16_END),
            XANDLER_INTERNAL(OnKey)
        ));

        // ItsWindow の背景色を薄緑色にする
        SetBackgroundColor(COLOR_ITS_WINDOW_BACK);
    }
}

// デストラクタ
ItsWindow::~ItsWindow(Void)
{
}

// ItsWindow インスタンスを生成する NewInstance 関数
ItsWindowSmp ItsWindow::NewInstance(SFCErrorPtr exception)
{
    return static_pointer_cast<ItsWindow>(Factory(:: new ItsWindow, exception));
}

// ItsWindow 上の各種コンテナおよびコントロールを作成する関数
SFCError ItsWindow::Make(Void)
{
    SFYContainerSmp container;
    SFZContainerScrollBarControlSmp bar;
    SFCError error(SFERR_NO_ERROR);

    // 汎用コンテナを作成する
    if ((container = SFZContainer::NewInstance(&error)) != null) {

        // コンテナの親をウィンドウに設定する
        if ((error = container->SetParent(GetThis())) == SFERR_NO_ERROR) {

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

            // 仮想領域を実領域より下に 150 だけ伸張する
            container->SetVirtualBound(SFXRectangle(container->GetRealBound()).AddHeight(150));

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

            SFZTextButtonControlSmp button;

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

                // ボタンコントロールの親をコンテナに設定する
                if ((error = button->SetParent(container)) == SFERR_NO_ERROR) {

                    // ボタンコントロールの文字列を "CenterMiddle" に設定する
                    if ((error = button->SetText("CenterMiddle")) == SFERR_NO_ERROR) {

                        // ボタンコントロールをコンテナのローカル領域の中央に配置する
                        button->SetRealBound(button->GetSuitableBound(container->GetLocalBound()).SnapCenterMiddle(container->GetLocalBound().GetCenterMiddle()));

                        // ボタンコントロールの状態を「可視+活性+操作可能+フォーカス」にまとめて設定する
                        button->SetState(true, true, true, true);
                    }
                }
            }
        }
    }
    if (error == SFERR_NO_ERROR) {

        // コンテナ専用のスクロールバーコントロールを作成する
        if ((bar = SFZContainerScrollBarControl::NewInstance(&error)) != null) {

            // 親をウィンドウに設定する
            if ((error = bar->SetParent(GetThis())) == SFERR_NO_ERROR) {

                // コンテナの右隣にスクロールバーコントロールを配置する
                // * スクロールバーの幅は 5
                SFXRectangle rx;
                rx.Set(container->GetRealBound());
                rx.AddX(rx.GetWidth());
                rx.SetWidth(5);
                bar->SetRealBound(rx);

                // スクロールバーコントロールの状態を 「可視+活性+操作不能+非フォーカス」にまとめて設定する
                // * この状態設定により、スクロールバーコントロールにフォーカスが移動することはない
                bar->SetState(true, true, false, false);

                /// スクロールバーコントロールをコンテナに結びつける
                error = bar->Bind(container);
            }
        }
    }
    return error;
}

// ItsWindow のキーハンドラの実装
XANDLER_IMPLEMENT_BOOLEVENT(ItsWindow, OnKey, invoker, event)
{
    unused(invoker);

    Bool result(false);

    switch (event.GetP16()) {

        // クリアキーの SFEVT_KEY イベントを受信したとき
        case AVK_CLR:

            // ItsWindow を終了する
            Terminate();

            result = true;

            break;
    }
    return result;
}

初期画面で 3 キーが押されると、 ItsWindow を表示するようにします。

例 3.52. helloworld アプリケーションクラスにおける ItsWindow の作成

// helloworld アプリケーションクラスの定義
SFMTYPEDEFCLASS(helloworld)  //  便利な型を生成するマクロ
class helloworld : public SFYApplication {

    SFMSEALCOPY(helloworld)  // インスタンスのコピーを禁止するマクロ
private:
    MyWindowSmp _myWindow;
    SFZTextMenuSmp _textMenu;

    // *** 太字が追加部分

    // ItsWindow のスマートポインタ
    ItsWindowSmp _itsWindow;

public:
    static SFCInvokerPtr Factory(Void);
private:
    explicit helloworld(Void) static_throws;
    virtual ~helloworld(Void);
    SFCError MakeMy(Void);
    SFCError MakeMenu(Void);
    SFCError MakeColorDialog(UserColorConstRef color);

    // ItsWindow 作成
    SFCError MakeIts(Void);

    Void SetMenuColors(UserColorConstRef color);

    XANDLER_DECLARE_VOIDRENDER(OnRenderRequest)  // 描画ハンドラ
    XANDLER_DECLARE_BOOLEVENT(OnKey)             // キーハンドラ
    XANDLER_DECLARE_VOIDRESULT(OnMenuResult)     // 結果ハンドラ
};

// ItsWindow を作成する関数
SFCError helloworld::MakeIts(Void)
{
    SFCError error(SFERR_NO_ERROR);

    // ItsWindow インスタンスを作成する
    if ((_itsWindow = ItsWindow::NewInstance(&error)) != null) {

        // ItsWindow の親をルートに設定する
        error = _itsWindow->SetParent(GetThis());

        if (error == SFERR_NO_ERROR) {

            // ItsWindow の実領域を携帯電話画面から(10, 10)だけ Deflate した領域に設定する
            _itsWindow->SetRealBound(GetLocalBound().Deflate(10, 10));

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

            // ItsWindow を最前面に移動する
            _itsWindow->ToFront();

            // ItsWindow のコントロールを作成する
            _itsWindow->Make();
        }
    }
    return error;
}

// helloworld アプリケーションクラスの描画ハンドラの実装
XANDLER_IMPLEMENT_VOIDRENDER(helloworld, OnRenderRequest, invoker, reason, graphics)
{
    unused(invoker);
    unused(reason);

    // helloworld アプリケーションクラス(ルート)のローカル領域(携帯電話の画面)の背景は
    // SetBackgroundColor 関数で設定した色(デフォルト: 白色)で塗り潰される

    // テキストを描画する
    graphics->DrawSingleText("Key 1 - Controls", SFXGrid(20, 20), GetLocalBound(), COLOR_BLACK);
    graphics->DrawSingleText("Key 2 - TextMenu", SFXGrid(20, 40), GetLocalBound(), COLOR_BLACK);

    graphics->DrawSingleText("Key 3 - Container", SFXGrid(20, 60), GetLocalBound(), COLOR_BLACK);

    return;
}

// helloworld アプリケーションクラスのキーハンドラの実装
XANDLER_IMPLEMENT_BOOLEVENT(helloworld, OnKey, invoker, event)
{
    unused(invoker);

    Bool result(false);

    if (this->GetChildFront(true, false, false, false) == null) {

        switch (event.GetP16()) {

            case AVK_SELECT:    // セレクトキーの SFEVT_KEY イベントを受信したとき

                Terminate();
                result = true;
                break;

            case AVK_1:         // 1 キーの SFEVT_KEY イベントを受信したとき

                TRACE("key 1");
                if (MakeMy() == SFERR_NO_ERROR) {
                    result = true;
                }
                break;

            case AVK_2:         // 2 キーの SFEVT_KEY イベントを受信したとき

                TRACE("key 2");
                if (MakeMenu() == SFERR_NO_ERROR) {
                    result = true;
                }
                break;

            case AVK_3:         // 3 キーの SFEVT_KEY イベントを受信したとき

            TRACE("key 3");

                // ItsWindow を作成する
                if (MakeIts() == SFERR_NO_ERROR) {

                    result = true;
                }
                break;
        }
    }

    return result;
}

参照: コンテナ(基礎編)

3.8.2. カスタムコンテナ

下図の枠付きのカスタムコンテナ CustomContainer を定義します。

[Note] 注意

枠はコンテナの実領域(可視領域)の境界上に黒色の点線で描画されます。

図 3.31. カスタムコンテナ

カスタムコンテナ

SFYContainer(抽象コンテナ)を継承するカスタムコンテナ CustomContainer を定義します。

例 3.53. CustomContainer クラスの定義

// CustomContainer クラスの定義
SFMTYPEDEFRESPONDER(CustomContainer)  //  便利な型を生成するマクロ
class CustomContainer : public SFYContainer
{
    SFMSEALRESPONDER(CustomContainer)  // インスタンスのコピーを禁止するマクロ

    // SFYResponder からこのクラスに至るまでの継承順序を指定するマクロ
    SFMRESPONDERINSTANTIATETHREE(CustomContainer, SFYContainer, SFYWidget, SFYResponder)
public:

    // 小文字アルファベットまたは記号 4 文字からなるタイプは予約されているので
    // CustomContainer のタイプを大文字アルファベット('C', 'C', 'T', 'N')で定義する
    enum CodeEnum {
        CODE_TYPE = four_char_code('C', 'C', 'T', 'N')
    };
    SFMTYPEDEFTYPE(CodeEnum)

public:
    static CustomContainerSmp NewInstance(SFCErrorPtr exception = null);

protected:
    explicit CustomContainer(Void) static_throws;
    virtual ~CustomContainer(Void);

    // 描画ハンドラ
    virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const;
};

// コンストラクタ
CustomContainer::CustomContainer(Void) static_throws
{
    if (static_try()) {
        SetType(CODE_TYPE);
    }
}

// デストラクタ
CustomContainer::~CustomContainer(Void)
{
}

// CustomContainer インスタンスを生成する NewInstance 関数の実装
CustomContainerSmp CustomContainer::NewInstance(SFCErrorPtr exception)
{
    return static_pointer_cast<CustomContainer>(Factory(:: new CustomContainer, exception));
}

// CustomContainer の描画ハンドラの実装
Void CustomContainer::HandleRenderRequest(SFXGraphicsPtr graphics) const
{
    AEEStrokeStyle style;   // 線種

    // 描画前の線種を記憶しておく
    style = graphics->GetStrokeStyle();

    // 線種を点線に設定する
    graphics->SetStrokeStyle(STROKE_DOTTED);

    // CustomContainer のローカル領域からみた実際に描画される領域(可視領域)を計算する
    // 可視領域は仮想領域と原点を 0 とする実領域サイズの領域との重なり部分になる
    // また、描画はローカル領域上に行われるため、可視領域のグリッド座標は、
    // 仮想領域のグリッド座標をマイナスにした値となる
    SFXRectangle rx;
    rx.Set(GetVirtualBound());
    rx.Set(SFXGrid(-rx.GetX(), -rx.GetY()), GetRealBound().GetSize());

    // 可視領域境界上に黒色の点線を描画する
    graphics->DrawRectangle(rx, COLOR_BLACK);

    // 線種を元に戻す
    graphics->SetStrokeStyle(style);

    return;
}

汎用コンテナ(SFZContainer)をカスタムコンテナ CustomContainer に置き換えます。

[Note] 注意

簡略化のため、 ここではボタンコントロールはコンテナ内に配置していません。

例 3.54.

// ItsWindow 上のコンテナとスクロールバーを作成する関数
SFCError ItsWindow::Make(Void)
{
    SFYContainerSmp container;
    SFZContainerScrollBarControlSmp bar;
    SFCError error(SFERR_NO_ERROR);

    // *** 太字が修正部分

    // カスタムコンテナを作成する
    if ((container = CustomContainer::NewInstance(&error)) != null) {

        // コンテナの親をウィンドウに設定する
        if ((error = container->SetParent(GetThis())) == SFERR_NO_ERROR) {

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

            // 仮想領域を実領域より下に 150 だけ伸張する
            container->SetVirtualBound(container->GetLocalBound().AddHeight(150));

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

            // 前節のボタンコントロールは配置しない //
        }
    }
    if (error == SFERR_NO_ERROR) {

        // スクロールバーコントロール(コンテナ専用)を作成する
        // ...(省略)...

    }
    return error;
}

参照: コンテナを表す抽象クラス[SFYContainer]