前のページ次のページ上に戻るホーム BREW C++ ライブラリ & GUI フレームワーク & XML ミドルウェア : SophiaFramework UNIVERSE 5.0

9.15. メニュー(基礎編)

メニューは、ルート内に配置されるように設計されたレスポンダです。

すべてのメニューは SFYMenu クラスを継承し、一定時間経過後に自動的にメニューを閉じる機能とデフォルトのキー操作機能を提供します。

具象メニューはアプレット開発ですぐに使うことができる部品であり、抽象メニューはカスタマイズされたユーザー定義メニューを作成するための起点となります。

表 9.19. 具象メニューの種類

クラス名 解説
SFZTextMenu テキストメニューです。
SFZGridMenu グリッドメニューです。

表 9.20. 抽象メニューの種類

クラス名 解説
SFYMenu メニューを表す抽象クラスです。
[Important] 重要

すべてのメニューにおいて、SFYResponder::SetParent 関数、SFYResponder::SetState 関数、SFYResponder::SetRealBound 関数の呼び出しは必須です。

その他の関数は必要に応じて呼び出します。省略することも可能です。

9.15.1. テキストメニュー [SFZTextMenu]

図 9.40. 動作例

動作例

SFZTextMenu クラスはテキスト形式のメニュー(テキストメニュー)を生成、制御、更新、破棄するためのクラスです。

テキストメニューには、ページ形式(デフォルト)とスクロール形式の 2 種類があります。

テキストメニューのデザインは、用意された様々な関数で変更可能です。

テキストや、絵文字、イメージをメニュー項目に設定できます。

例 9.70. 宣言

SFMTYPEDEFCLASS(USRApplication)
class USRApplication : public SFYApplication {
    SFMSEALCOPY(USRApplication)
private:
    SFZTextMenuSmp _menu;

    ...
private:
    SFCError Make(Void);

    // メニュー項目選択イベントのハンドラ
    XANDLER_DECLARE_VOIDRESULT(OnResult)
};

例 9.71. 実装

SFCError USRApplication::Make(Void)
{
    SFXRectangle rectangle;
    SInt16 i;
    SFCError error(SFERR_NO_ERROR);

    if ((_menu = SFZTextMenu::NewInstance(&error)) != null) {
        error = _menu->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            // メニュー項目選択イベントを処理するハンドラを登録する
            error = _menu->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnResult)
            );
            if (error == SFERR_NO_ERROR) {

                // メニュータイトルを設定する
                // SFXWideString オブジェクトの設定 (※リソースファイルから設定可能 )
                error = _menu->SetTitle("Text Menu");
                if (error == SFERR_NO_ERROR) {
                    for (i = 0; i < 3; ++i) {

                        // メニュー項目を追加する
                        // SFXWideString オブジェクトの設定 (※リソースファイルから設定可能 )
                        error = _menu->AppendItem(SFXWideString::Format("Menu item %d", i));

                        if (error != SFERR_NO_ERROR) break;
                    }
                    if (error == SFERR_NO_ERROR) {

                        // メニューを画面中央に配置する

                        // メニューの最適な領域のサイズを計算する
                        rectangle.Set(_menu->GetSuitableBound(GetLocalBound().Deflate(10, 0)));
                        rectangle.SetHeight(_menu->GetTitleHeight() + 3 * _menu->GetItemHeight());

                        // メニューの最適な領域を画面の中央に配置する
                        rectangle.SnapCenterMiddle(GetLocalBound().GetCenterMiddle());

                        // メニューの実領域を設定する
                        _menu->SetRealBound(rectangle);

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

                        // メニューを最前面に移動する
                        _menu->ToFront();
                    }
                }
            }
        }
    }
    return error;
}

// メニュー項目選択イベントを処理するハンドラ
XANDLER_IMPLEMENT_VOIDRESULT(USRApplication, OnResult, invoker, reason, result)
{
    SFXWideString text;

    switch (reason) {
        case SFP16_RESULT_OK:

            // メニュー項目が選択された場合に受信され、result は GetSelect 関数の戻り値となる
            text = _menu->GetItemText(result);
            TRACE("%S", text.GetCString());
            break;
        case SFP16_RESULT_ESCAPE:

            // クリアキー押下時、result は 常に 0 となる
            break;
    }
    return;
}

9.15.2. グリッドメニュー [SFZGridMenu]

図 9.41. 動作例

動作例

SFZGridMenu クラスはマトリックス形式のメニュー(グリッドメニュー)を生成、制御、更新、破棄するためのクラスです。

グリッドメニュー内のセルサイズはすべて同一で、実領域のサイズ、行と列の数に基づいて自動的に設定されます。

グリッドメニューのデザインは、用意された様々な関数で変更可能です。

テキストやイメージをメニュー項目に設定できます。

例 9.72. 宣言

SFMTYPEDEFCLASS(USRApplication)
class USRApplication : public SFYApplication {
    SFMSEALCOPY(USRApplication)
private:
    SFZGridMenuSmp _menu;

    ...
private:
    SFCError Make(Void);

    // メニュー項目選択イベントのハンドラ
    XANDLER_DECLARE_VOIDRESULT(OnResult)
};

例 9.73. 実装

SFCError USRApplication::Make(Void)
{
    SFBShellSmp shell;
    SFBImageSmp image;
    SFBImageSmp selectedImage;
    SInt16 i;
    SFCError error(SFERR_NO_ERROR);

    if ((_menu = SFZGridMenu::NewInstance(&error)) != null) {
        error = _menu->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            // メニュー項目選択イベントを処理するハンドラを登録する
            error = _menu->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnResult)
            );
            if (error == SFERR_NO_ERROR) {

                // メニュータイトルを設定する
                // SFXWideString オブジェクトの設定 (※リソースファイルから設定可能 )
                error = _menu->SetTitle("Text Menu");
                if (error == SFERR_NO_ERROR) {

                    // メニュータイトルのテキストを白色に設定する
                    _menu->SetTitleForeColor(SFXRGBColor(0xFF, 0xFF, 0xFF, 0x00));

                    // メニュータイトルの背景を水色に設定する
                    _menu->SetTitleBackColor(SFXRGBColor(0x00, 0xBF, 0xF3, 0x00));

                    // 行の数と列の数を設定する
                    _menu->SetRowCol(4, 3);

                    // SFBShell クラスのインスタンスを取得する
                    shell = SFBShell::GetInstance();
                    if (shell != null) {
                        for (i = 0; i < 12; ++i) {

                            // リソースファイルと ID からメニュー項目イメージを取得する
                            image = shell->LoadResImage(NEWWORLD_RES_FILE, IDI_OBJECT_5001 + i);

                            // 選択時のメニュー項目イメージを取得する
                            selectedImage = shell->LoadResImage(MENU_RES_FILE, IDI_OBJECT_5001 + i);

                            // メニュー項目を追加する
                            // SFXWideString オブジェクトの設定 (※リソースファイルから設定可能 )
                            error = _menu->AppendItem(SFXWideString::Format("%d", i), image, selectedImage);

                            if (error != SFERR_NO_ERROR) break;
                        }

                        if (error == SFERR_NO_ERROR) {

                            // メニュー項目名を表示するようにする
                            _menu->SetDrawItemText(true);

                            // メニューの実領域を画面全体に設定する
                            _menu->SetRealBound(GetLocalBound());

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

                            // メニューを最前面に移動する
                            _menu->ToFront();
                        }
                    }
                }
            }
        }
    }
    return error;
}

// メニュー項目選択イベントを処理するハンドラ
XANDLER_IMPLEMENT_VOIDRESULT(USRApplication, OnResult, invoker, reason, result)
{
    switch (reason) {
        case SFP16_RESULT_OK:

            // メニュー項目が選択された場合に受信され、result は GetSelect 関数の戻り値となる
            TRACE("%d", result);
            break;
        case SFP16_RESULT_ESCAPE:

            // クリアキー押下時、result は 常に 0 となる
            break;
    }
    return;
}

9.15.3. メニューを表す抽象クラス[SFYMenu]

各種メニューを実装するための起点となります。

このクラスは、一定時間経過後に自動的にメニューを閉じる機能と操作キーの管理を実装し、いくつかの仮想関数のデフォルトの動作も実装します。

表 9.21. 仮想関数名とデフォルトの動作

仮想関数名 デフォルトの動作 オーバーライド
SFYMenu::HandleOperateKey 結果イベントを送信※1 任意
SFYMenu::HandleEscapeKey 結果イベントを送信※2 任意
SFYMenu::HandleSelectUpKey 任意
SFYMenu::HandleSelectDownKey 任意
SFYMenu::HandleSelectLeftKey 任意
SFYMenu::HandleSelectRightKey 任意
SFYWidget::HandleBoundRequest 推奨
SFYWidget::HandleBoundOptimize 推奨
SFYMenu::HandleBoundReal 仮想領域を調整※3 任意
SFYWidget::HandleBoundVirtual 任意
SFYWidget::HandleBoundGlobal 任意
SFYWidget::HandleRenderRequest 必須
[Note] 注釈

※1.InvokeForward(SFXEvent(SFEVT_RESPONDER_RESULT, SFP16_RESULT_CANCEL, 0), false) を実行します。

※2.InvokeForward(SFXEvent(SFEVT_RESPONDER_RESULT, SFP16_RESULT_ESCAPE, 0), false) を実行します。

※3.SetVirtualBound(SFXRectangle(SFXGrid::ZeroInstance(), GetRealBound().GetSize())) を実行します。つまり、仮想領域を実領域に一致させます。

以下にユーザー定義メニューを作成するときに最低限必要なコードを示します。

例 9.74. 宣言

SFMTYPEDEFRESPONDER(USRMenu)
class USRMenu : public SFYMenu {
    SFMSEALRESPONDER(USRMenu)
    SFMRESPONDERINSTANTIATETHREE(USRMenu, SFYMenu, SFYWidget, SFYResponder)
public:

    // レスポンダのタイプを定義する
    // 小文字と記号のみからなるタイプは予約されているので使えない
    enum CodeEnum {
        CODE_TYPE = four_char_code('U', 'M', 'N', 'U')
    };
    SFMTYPEDEFTYPE(CodeEnum)

public:
    static USRMenuSmp NewInstance(SFCErrorPtr exception = null);
protected:
    explicit USRMenu(Void) static_throws;
    virtual ~USRMenu(Void);

    // 親クラスで定義されている仮想関数のうち、実装が推奨される仮想関数
    virtual Void HandleOperateKey(Void);
    virtual Void HandleSelectUpKey(Void);
    virtual Void HandleSelectDownKey(Void);
    virtual Void HandleBoundRequest(SFXRectanglePtr rectangle) const;
    virtual Void HandleBoundOptimize(SFXRectanglePtr rectangle) const;
    virtual Void HandleBoundReal(Void);
    virtual Void HandleBoundVirtual(Void);
    virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const;
};

例 9.75. 実装

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

        // レスポンダのタイプを設定する
        SetType(CODE_TYPE);

        // 初期化処理を記述する
    }
}

USRMenu::~USRMenu(Void)
{
    // 終了処理を記述する
}

USRMenuSmp USRMenu::NewInstance(SFCErrorPtr exception)
{
    return static_pointer_cast<USRMenu>(Factory(::new USRMenu, exception));
}

Void USRMenu::HandleOperateKey(Void)
{
    // セレクトキー押下時に必要な処理があれば、ここに記述する
    // 通常、以下のようにイベントを送信する
    // _select 変数は選択されている項目の番号を表すものとする
    InvokeForward(SFXEvent(SFEVT_RESPONDER_RESULT, SFP16_RESULT_OK, _select), false);
    return;
}

Void USRMenu::HandleSelectUpKey(Void)
{
    // 上キー押下時に必要な処理があれば、ここに記述する
    // 例:選択されている項目を1つ戻すなど
    return;
}

Void USRMenu::HandleSelectDownKey(Void)
{
    // 下キー押下時に必要な処理があれば、ここに記述する
    // 例:選択されている項目を1つ進めるなど
    return;
}

Void USRMenu::HandleBoundRequest(SFXRectanglePtr rectangle) const
{
    // メニューに最適な大きさを計算して rectangle パラメータに設定する
    // 原点は変更せず、サイズだけを設定することを推奨

    return;
}

Void USRMenu::HandleBoundOptimize(SFXRectanglePtr rectangle) const
{
    // メニューに最適な大きさを rectangle パラメータ内の大きさに
    // 収まるように計算し、rectangle パラメータに設定する
    // 原点は変更せず、サイズだけを設定することを推奨

    return;
}

Void USRMenu::HandleBoundReal(Void)
{
    // 実領域が変更された場合に再計算が必要なものがあれば、ここに記述する
    return;
}

Void USRMenu::HandleBoundVirtual(Void)
{
    // 仮想領域が変更された場合に再計算が必要なものがあれば、ここに記述する
    return;
}

Void USRMenu::HandleRenderRequest(SFXGraphicsPtr graphics) const
{
    // メニューを描画する
    return;
}