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

3.3. コントロール

3.3.1. ボタン

図のようにボタンを配置するコードを追加します。

ボタン 1 とボタン 2 は排他的に動作し、ボタン 3 は "Hello Window" 文字列表示の ON/OFF を切り替えるように実装します。

図 3.4. ボタン

ボタン

ボタン コントロール と ボタンが押されたときに実行するハンドラ の宣言を行います。

例 3.12. ボタン コントロール と ボタン ハンドラ の宣言

SFMTYPEDEFRESPONDER(MyWindow)
class MyWindow : public SFZWindow
{
    SFMSEALRESPONDER(MyWindow)
    SFMRESPONDERINSTANTIATEFOUR(MyWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
public:
    enum CodeEnum {
        CODE_TYPE = four_char_code('M', 'W', 'N', 'D')
    };
    SFMTYPEDEFTYPE(CodeEnum)
private:

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

    // ボタン コントロールの宣言
    SFZTextButtonControlSmp _button1;
    SFZTextButtonControlSmp _button2;
    SFZTextButtonControlSmp _button3;

    // "Hellow World" 表示 ON/OFF 切り替えフラグ
    Bool _flagShowHw; 
public:
    static MyWindowSmp NewInstance(SFCErrorPtr exception = null);

    // MyWindow 上のレスポンダ (コントロール) を作成します。
    SFCError Make(Void);
protected:
    explicit MyWindow(Void) static_throws;
    virtual ~MyWindow(Void);

    virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const;
    XANDLER_DECLARE_BOOLEVENT(OnKey)

    // ボタン ハンドラの宣言
    // ボタン 1 と ボタン 2 のハンドラは共通にします。
    XANDLER_DECLARE_VOIDRESULT(OnButton12)
    XANDLER_DECLARE_VOIDRESULT(OnButton3)
private:

    // ボタンの作成
    SFCError CreateButtons(SFXGridPtr offs);
};
[Note] XANDLER_DECLARE_VOIDRESULT マクロについて

ボタンを押すとコントロールに対して結果イベントが送られます。XANDLER_DECLARE_VOIDRESULT マクロは結果イベントを受けとるハンドラを宣言するのに用いられる便利なマクロです。

一方ハンドラの定義では、 XANDLER_IMPLEMENT_VOIDRESULT マクロを用います。

MyWindow 上のコントロールをここで作成します。

例 3.13. レスポンダの作成

#define X_MARGIN 8
#define Y_MARGIN 8
#define ID_BUTTON1 1
#define ID_BUTTON2 2

// MyWindow 上のレスポンダ作成
SFCError MyWindow::Make(Void)
{
    SFCError error;

    // MyWindowのローカル領域を基準としたボタンの相対座標を計算します。
    SFXGrid offset(X_MARGIN, Y_MARGIN);

    // ボタンを作成します。
    if ((error = CreateButtons(&offset)) != SFERR_NO_ERROR) {
        return error;
    }

    return error;
}
[Note] ローカル領域とは

ローカル領域は原点が常に (0, 0) となります。

詳細は、ローカル領域を参照してください。

ボタンのインスタンス作成と初期化を行うコードを追加します。

ここで、ボタンのテキストや属性をカスタマイズします。

例 3.14. ボタンのインスタンス作成 と 初期化

// ボタンの作成
SFCError MyWindow::CreateButtons(SFXGridPtr offs)
{
    SFCError error;
    SFXGraphicsPtr graphics = SFXGraphics::GetInstance();
    SInt16Const height = graphics->GetFontHeight() + 4;
    SInt16Const width = (GetVirtualBound().GetWidth() - 4 * X_MARGIN) / 3;
    SFXRectangle rect(*offs, SFXSize(width, height));

    // ボタン 1
    // ボタンのインスタンスを作成します。
    if ((_button1 = SFZTextButtonControl::NewInstance(&error)) != null) {

        // 親レスポンダを設定します。
        error = _button1->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            // ハンドラを登録しておくことでボタン操作時にイベントを受信できます。
            error = _button1->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnButton12)
            );
            if (error == SFERR_NO_ERROR) {

                // 表示するテキストを設定します。
                error = _button1->SetText("OK");
                if (error == SFERR_NO_ERROR)

                    // ボタンを識別するIDを設定します。
                    _button1->SetID(ID_BUTTON1);

                    // ボタンを表示する位置と領域を指定します。
                    _button1->SetRealBound(rect);

                    // ボタンの状態を設定します。 (visible, active, enable, focus)
                    _button1->SetState(true, true, true, true);
            }
        }
    }

    // ボタン 2
    if ((_button2 = SFZTextButtonControl::NewInstance(&error)) != null) {
        error = _button2->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _button2->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnButton12)
            );
            if (error == SFERR_NO_ERROR) {
                error = _button2->SetText("NG");
                if (error == SFERR_NO_ERROR) {
                    _button2->SetID(ID_BUTTON2);

                    // ボタンの領域を右にずらします。
                    rect.Offset(X_MARGIN + rect.GetWidth(), 0);
                    _button2->SetRealBound(rect);
                    _button2->SetState(true, false, false, false);
                }
            }
        }
    }

    // ボタン 3
    if ((_button3 = SFZTextButtonControl::NewInstance(&error)) != null) {
        error = _button3->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _button3->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnButton3)
            );
            if (error == SFERR_NO_ERROR) {
                error = _button3->SetText("Off");
                if (error == SFERR_NO_ERROR) {
                    rect.Offset(X_MARGIN + rect.GetWidth(), 0);
                    _button3->SetRealBound(rect);
                    _button3->SetState(true, true, true, false);
                }
            }
        }
    }

    // オフセットを更新します。
    offs->AddY(rect.GetHeight() + Y_MARGIN);

    return error;
}
[Note] 図形クラス

SophiaFramework では 長方形を表すクラス SFXRectangle、 座標の1点を表すクラス SFXGrid、幅と高さを表すクラスSFXSize など便利な図形を表すクラスがあります。

詳細は、図形と色を参照してください。

MyWindow 作成時にレスポンダ(コントロール)も作成されるように HelloWorld::Make() で _myWindow->Make() を呼び出します。

例 3.15. レスポンダ作成関数の呼び出し

// MyWindow 作成
SFCError HelloWorld::Make(Void)
{
    SFCError error(SFERR_NO_ERROR);
    if ((_myWindow = MyWindow::NewInstance(&error)) != null) {
        error = _myWindow->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            _myWindow->SetRealBound(_myWindow->GetSuitableBound(GetLocalBound().Deflate(15, 20)));
            _myWindow->SetState(true, true, true, true);
            _myWindow->ToFront();

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

            // MyWindow 上のレスポンダ 作成
            _myWindow->Make();
        }
    }
    return error;
}

MyWindow クラスのコンストラクタで文字列表示フラグを true に初期化しておきます。

例 3.16. MyWindow コンストラクタの変更

// コンストラクタ// *** 太字が変更部分MyWindow::MyWindow(Void) : _ifShowHw(true) static_throws
{
    if (static_try()) {
        SetType(CODE_TYPE);
    }
    if (static_try()) {
        static_throw(RegisterHandler(
            SFXEventRange(SFEVT_KEY, SFEVT_KEY, SFP16_BEGIN, SFP16_END),
            XANDLER_INTERNAL(OnKey)
        ));
    }
}

ボタンが押されたときに実行するハンドラを追加します。

ボタン 1 と ボタン 2 が排他的に動作するように、ボタンの活性/不活性を切り替えます。

例 3.17. ボタン 1 と ボタン 2 のハンドラ実装

// ボタン 1 と ボタン 2 のハンドラ
XANDLER_IMPLEMENT_VOIDRESULT(MyWindow, OnButton12, invoker, reason, result)
{
    unused(reason);
    unused(result);

    // 押されたボタンを取得します。
    SFZTextButtonControlSmp pushed(static_cast<SFZTextButtonControlPtr>(invoker));

    // 対になるボタンを取得します。
    UInt32 pairID = (pushed->GetID() == ID_BUTTON1) ? ID_BUTTON2 : ID_BUTTON1;
    SFZTextButtonControlSmp pair = static_pointer_cast<SFZTextButtonControl>(GetThis()->GetChildFront(pairID));

    // 押されたボタンを "不活性" にします。
    // 意味は、pushed->SetState(true, false, false, false); と同じになります。
    pushed->SetText("NG");
    pushed->SetStateActive(false);

    // 対になるボタンを "活性/操作可能/フォーカス" にします。
    pair->SetText("OK");
    pair->SetStateActive(true);
    pair->SetStateEnable(true);
    pair->SetStateFocus(true);

    return;
}

レスポンダにはユニークな ID を設定することができ、ID でそのレスポンダを検索することができます。

ボタン 1 と ボタン 2 に SetID 関数でID を設定することにより、GetID 関数で そのID を取得しています。

設定したID を検索するには、親レスポンダに対して GetChildFront 関数を呼び出します。

invoker は 呼び出し元レスポンダのポインタですが、SFYResponderPtr 型になっています。

そのため、一度 static_cast 演算子で SFZTextButtonControlPtr 型にキャストし、スマートポインタへとさらに変換しています。

[Caution] スマートポインタのキャスト演算子

GetChildFront 関数の戻り値は SFYResponderSmp となっているため、SFZTextButtonControl クラスのスマートポインタに変換するのに、static_pointer_cast 演算子を用いています。

[Note] レスポンダの状態

レスポンダの状態には 有効状態、可視状態、活性状態、操作可能状態、フォーカス状態の5種類があります。

SetState 関数で設定できるのは、可視状態、活性状態、操作可能状態、フォーカス状態の4種類です。

上記のボタン ハンドラで用いていますが、それぞれ1つの状態のみを設定できる関数も用意されています。

詳細は、レスポンダの状態を参照してください。

ボタン 3 では "Hello Window" 文字列の ON/OFF を切り替えます。

例 3.18. ボタン 3 のハンドラ実装

// ボタン 3 のハンドラ
XANDLER_IMPLEMENT_VOIDRESULT(MyWindow, OnButton3, invoker, reason, result)
{
    unused(invoker);
    unused(reason);
    unused(result);

    // ボタンのラベルを切り替えます。
    _ifShowHw = !_ifShowHw;
    _button3->SetText(_ifShowHw ? "Off" : "On");

    // MyWindow を再描画します。
    Render(true);

    return;
}

ON/OFF の切り替えに対応するために、MyWindow の描画ハンドラ を変更します。

例 3.19.

// ウィンドウの描画ハンドラ
Void MyWindow::HandleRenderRequest(SFXGraphicsPtr graphics) const
{
    // ウィンドウ全体を薄緑色に描画します。
    graphics->FillRectangle(GetLocalBound(), COLOR_MY_WINDOW_BACK);

    // 表示が On のときのみ、"Hello Window" を表示します。
    if (_flagShowHw) {
        graphics->DrawSingleText("Hello Window", GetVirtualBound(), COLOR_BLACK);
    }

    return;
}

シミュレータでの実行結果です。

  1. 1 キーを押すと、ウィンドウが表示されます。
  2. ボタン 1 を押すと、ボタン 1 が無効になりボタン 2 が有効になります。
  3. 逆にボタン 2 を押すと、ボタン 2 が無効になりボタン 1 が有効になります。
  4. ボタン 3 を押すと、"Hello Window" 表示の ON/OFF が切り替わります。
  5. クリアー キーを押すと、ウィンドウが閉じます。

図 3.5. 手順 2 の結果

手順 2 の結果

図 3.6. 手順 4 の結果

手順 4 の結果

3.3.2. チェック ボックス

図のようにチェック ボックスを配置するコードを追加します。

チェック ボックス ハンドラでチェックされたときの状態をデバッグ表示します。

図 3.7. チェック ボックス

チェック ボックス

チェック ボックス コントロール と チェックされたときに実行するハンドラ の宣言を行います。

例 3.20. チェック ボックス コントロール と ハンドラ の宣言

SFMTYPEDEFRESPONDER(MyWindow)
class MyWindow : public SFZWindow {
    SFMSEALRESPONDER(MyWindow)
    SFMRESPONDERINSTANTIATEFOUR(MyWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
public:
    enum CodeEnum {
        CODE_TYPE = four_char_code('M', 'W', 'N', 'D')
    };
    SFMTYPEDEFTYPE(CodeEnum)
private:
    SFZTextButtonControlSmp _button1;
    SFZTextButtonControlSmp _button2;
    SFZTextButtonControlSmp _button3;
    Bool _flagShowHw;

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

    // チェック ボックス コントロールの宣言
    SFZCheckboxControlSmp _checkbox1;
    SFZCheckboxControlSmp _checkbox2;
public:
    static MyWindowSmp NewInstance(SFCErrorPtr exception = null);
    SFCError Make(Void);
protected:
    explicit MyWindow(Void) static_throws;
    virtual ~MyWindow(Void);

    virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const;
    XANDLER_DECLARE_BOOLEVENT(OnKey)
    XANDLER_DECLARE_VOIDRESULT(OnButton12)
    XANDLER_DECLARE_VOIDRESULT(OnButton3)

    // 共通チェック ボックス ハンドラ
    XANDLER_DECLARE_VOIDRESULT(OnCheck)
private:
    SFCError CreateButtons(SFXGridPtr offs);

    // チェック ボックスの作成
    SFCError CreateCheckBoxes(SFXGridPtr offs);
};

チェック ボックスが作成されるように MyWindow::Make() を変更します。

例 3.21. レスポンダの作成

// MyWindow 上のレスポンダ作成
SFCError MyWindow::Make(Void)
{
    SFCError error;

    SFXGrid offset(0, 0);

    offset.Add(X_MARGIN, Y_MARGIN);

    if ((error = CreateButtons(&offset)) != SFERR_NO_ERROR) {
        return error;
    }

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

    // チェック ボックスを作成します。
    if ((error = CreateCheckBoxes(&offset)) != SFERR_NO_ERROR) {
        return error;
    }

    return error;
}

チェック ボックスのインスタンス作成と初期化を行うコードを追加します。

ここで、チェック ボックスのテキストや属性をカスタマイズします。

例 3.22. チェック ボックスのインスタンス作成 と 初期化

// チェック ボックスの作成
SFCError MyWindow::CreateCheckBoxes(SFXGridPtr offs)
{
    SFCError error;
    SFXGraphicsPtr graphics = SFXGraphics::GetInstance();
    SInt16Const height = graphics->GetFontHeight() + 4;
    SInt16Const width = (GetVirtualBound().GetWidth() - 3 * X_MARGIN) / 2;
    SFXRectangle rect(*offs, width, height);

    // チェック ボックス 1
    // チェック ボックスのインスタンスを作成します。
    if ((_checkbox1 = SFZCheckboxControl::NewInstance(error)) != null) {
        error = _checkbox1->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _checkbox1->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnCheck)
            );
            if (error == SFERR_NO_ERROR) {
                error = _checkbox1->SetText("Hit");
                if (error == SFERR_NO_ERROR) {

                    // チェックボックスにチェックを入れます。
                    _checkbox1->SetCurrentValue(true);

                    // チェック ボックスを左側にアラインします。
                    _checkbox1->SetHorizontalAlign(SFZCheckboxControl::HORIZONTAL_LEFT);
                    _checkbox1->SetRealBound(rect);
                    _checkbox1->SetState(true, true, true, false);
                }
            }
        }
    }

    // チェック ボックス 2
    if ((_checkbox2 = SFZCheckboxControl::NewInstance(error)) != null) {
        error = _checkbox2->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _checkbox2->RegisterHandler(
             SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
             XANDLER_INTERNAL(OnCheck)
            );
            error = _checkbox2->SetText("Run");
            if (error == SFERR_NO_ERROR) {
                rect.Offset(X_MARGIN + rect.GetWidth(), 0);
                _checkbox2->SetHorizontalAlign(SFZCheckboxControl::HORIZONTAL_LEFT);
                _checkbox2->SetRealBound(rect);
                _checkbox2->SetState(true, true, true, false);
            }
        }
    }

    offs->AddY(rect.GetHeight() + Y_MARGIN);

    return error;
}
[Note] チェック ボックスのアライメントについて

ボタンでは割り当てたサイズだけ拡張されますが、チェック ボックスは固定サイズです。

必要以上のサイズを割り当てると、デフォルトでは中央にアラインされます。

SetHorizontalAlign 関数で水平方向のアライメントを変更することができます。

別の方法として、GetSuitableBound 関数で最適なサイズを計算してから、チェック ボックスに領域を割り当てることができます。

この方法ではアライメントを意識する必要はありません。

チェック ボックスにチェック状態が変更されたときに実行するハンドラを実装します。

チェック ボックスの状態をデバッグ ウィンドウに表示します。

例 3.23. チェック ボックス ハンドラの実装

// チェック ボックス ハンドラの実装
XANDLER_IMPLEMENT_VOIDRESULT(MyWindow, OnCheck, invoker, reason, result)
{
    unused(invoker);
    unused(reason);
    unused(result);

    // チェック ボックスの状態をデバッグ表示します。
    SFXWideString label1 = _checkbox1->GetText();
    SFXWideString label2 = _checkbox2->GetText();
    TRACE("%S: %d", label1.GetCString(), _checkbox1->GetCurrentValue());
    TRACE("%S: %d", label2.GetCString(), _checkbox2->GetCurrentValue());

    return;
}
[Note] チェック ボックスの状態取得

チェック ボックスの状態は GetCurrentValue 関数で取得できます。

[Caution] コントロールのラベル

GetText 関数で取得したラベルは、SFXWideString 型になります。

ワイド型文字列を TRACE 文で用いるために、S パラメータを用いています。

描画ハンドラ MyWindow::HandleRenderRequest() を変更します。

ここで、"Hello Window" 文字列を最初から表示しないように変更しておきます。

例 3.24.

// ウィンドウの描画ハンドラ
Void MyWindow::HandleRenderRequest(SFXGraphicsPtr graphics) const
{
    // ウィンドウ全体を薄緑色に描画します。
    graphics->FillRectangle(GetLocalBound(), COLOR_MY_WINDOW_BACK);

    // 何も表示しません。

    return;
}

シミュレータでの実行結果です。

図 3.8. 実行結果

実行結果

図 3.9. チェック ボックスにチェックを入れたときのデバッグ ウィンドウ ( チェック ボックスの状態が出力されます )

チェック ボックスにチェックを入れたときのデバッグ ウィンドウ ( チェック ボックスの状態が出力されます )

3.3.3. ラジオ ボタン

図のようにラジオ ボタンを配置するコードを追加します。

ラジオ ボタンをグループ化し、そのグループ内で排他的に動作するようにします。

図 3.10. ラジオ ボタン

ラジオ ボタン

ラジオ ボタン コントロール と 押されたときに実行するハンドラ の宣言を行います。

例 3.25. ラジオ ボタン コントロール と ハンドラ の宣言

SFMTYPEDEFRESPONDER(MyWindow)
class MyWindow : public SFZWindow {
    SFMSEALRESPONDER(MyWindow)
    SFMRESPONDERINSTANTIATEFOUR(MyWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
public:
    enum CodeEnum {
        CODE_TYPE = four_char_code('M', 'W', 'N', 'D')
    };
    SFMTYPEDEFTYPE(CodeEnum)
private:
    SFZTextButtonControlSmp _button1;
    SFZTextButtonControlSmp _button2;
    SFZTextButtonControlSmp _button3;
    Bool _ifShowHw;
    SFZCheckboxControlSmp _checkbox1;
    SFZCheckboxControlSmp _checkbox2;

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

    // ラジオ ボタン コントロールの宣言
    SFZRadiobuttonControlSmp _radio1;
    SFZRadiobuttonControlSmp _radio2;
public:
    static MyWindowSmp NewInstance(SFCErrorPtr exception = null);
    SFCError Make(Void);
protected:
    explicit MyWindow(Void) static_throws;
    virtual ~MyWindow(Void);

    virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const;
    XANDLER_DECLARE_BOOLEVENT(OnKey)
    XANDLER_DECLARE_VOIDRESULT(OnButton12)
    XANDLER_DECLARE_VOIDRESULT(OnButton3)
    XANDLER_DECLARE_VOIDRESULT(OnCheck)

    // ラジオ ボタン ハンドラ の宣言
    XANDLER_DECLARE_VOIDRESULT(OnRadio)
private:
    SFCError CreateButtons(SFXGridPtr offs);
    SFCError CreateCheckBoxes(SFXGridPtr offs);

    // ラジオ ボタンの作成
    SFCError CreateRadioButtons(SFXGridPtr offs);
};

ラジオ ボタンが作成されるように MyWindow::Make() を変更します。

例 3.26. レスポンダの作成

// MyWindow 上のレスポンダ作成
SFCError MyWindow::Make(Void)
{
    SFCError error;

    SFXGrid offset(0, 0);

    offset.Add(X_MARGIN, Y_MARGIN);

    if ((error = CreateButtons(&offset)) != SFERR_NO_ERROR) {
        return error;
    }
    if ((error = CreateCheckBoxes(&offset)) != SFERR_NO_ERROR) {
        return error;
    }

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

    // ラジオ ボタンを作成します。
    if ((error = CreateRadioButtons(&offset)) != SFERR_NO_ERROR) {
        return error;
    }

    return error;
}

ラジオ ボタンのインスタンス作成と初期化を行うコードを追加します。

ここで、ラジオ ボタンのテキストや属性をカスタマイズします。

例 3.27. ラジオ ボタンのインスタンス作成 と 初期化

// ラジオ ボタンの作成
SFCError MyWindow::CreateRadioButtons(SFXGridPtr offs)
{
    SFCError error;
    SFXGraphicsPtr graphics = SFXGraphics::GetInstance();
    SInt16Const height = graphics->GetFontHeight() + 4;
    SInt16Const width = (GetVirtualBound().GetWidth() - 3 * X_MARGIN) / 2;
    SFXRectangle rect(*offs, width, height);

    // ラジオ ボタン 1
    if ((_radio1 = SFZRadiobuttonControl::NewInstance(error)) != null) {
        error = _radio1->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _radio1->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnRadio)
            );
            if (error == SFERR_NO_ERROR) {
                error = _radio1->SetText("Fast");
                if (error == SFERR_NO_ERROR) {

                    // ラジオボタンにチェックを入れます。
                    _radio1->SetCurrentValue(true);
                    _radio1->SetHorizontalAlign(SFZRadiobuttonControl::HORIZONTAL_LEFT);
                    _radio1->SetRealBound(rect);
                    _radio1->SetState(true, true, true, false);
                }
            }
        }
    }

    // ラジオ ボタン 2
    if ((_radio2 = SFZRadiobuttonControl::NewInstance(error)) != null) {
        error = _radio2->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _radio2->SetParent(GetThis());
            if (error == SFERR_NO_ERROR) {
                error = _radio2->RegisterHandler(
                    SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                    XANDLER_INTERNAL(OnRadio)
                );
                if (error == SFERR_NO_ERROR) {
                    error = _radio2->SetText("Slow");
                    if (error == SFERR_NO_ERROR) {
                        rect.Offset(X_MARGIN + rect.GetWidth(), 0);
                        _radio2->SetHorizontalAlign(SFZRadiobuttonControl::HORIZONTAL_LEFT);
                        _radio2->SetRealBound(rect);
                        _radio2->SetState(true, true, true, false);
                    }
                }
            }
        }
    }

    // ラジオボタン1とラジオボタン2をグループ化します。
    _radio1->Group(_radio2);

    offs->AddY(rect.GetHeight() + Y_MARGIN);

    return error;
}
[Note] Group 関数

ラジオ ボタンは Group 関数を用いてグループ化する必要があります。

グループ化されたラジオ ボタンは排他的に動作します。

[Note] ラジオ ボタンのアライメントについて

チェック ボックスのアライメントと同様に、デフォルトでは中央にアラインされます。

ラジオ ボタンの状態が変更されたときに実行するハンドラを実装します。

ラジオ ボタンの状態をデバッグ ウィンドウに表示します。

例 3.28. ラジオ ボタンのハンドラの実装

// ラジオ ボタン ハンドラの実装
XANDLER_IMPLEMENT_VOIDRESULT(MyWindow, OnRadio, invoker, reason, result)
{
    unused(invoker);
    unused(reason);
    unused(result);

    // ラジオ ボタンの状態をデバッグ表示します。
    SFXWideString label1 = _radio1->GetText();
    SFXWideString label2 = _radio2->GetText();
    TRACE("%S: %d", label1.GetCString(), _radio1->GetCurrentValue());
    TRACE("%S: %d", label2.GetCString(), _radio2->GetCurrentValue());

    return;
}
[Note] ラジオ ボタンの状態取得

ラジオ ボタンの状態も GetCurrentValue 関数で取得できます。

シミュレータでの実行結果です。

図 3.11. 実行結果

実行結果

図 3.12. ラジオ ボタンが押されたときのデバッグ ウィンドウ ( ラジオ ボタンの状態が出力されます )

ラジオ ボタンが押されたときのデバッグ ウィンドウ ( ラジオ ボタンの状態が出力されます )

3.3.4. コンボ ボックス

図のようにコンボ ボックスを配置するコードを追加します。

図 3.13. コンボ ボックス

コンボ ボックス
[Note] 自動スクロール バー

コンボ ボックスでは項目数が多いとき、自動的にスクロールバーが追加されます。

コンボ ボックス コントロール と 状態が変更されたときに実行するハンドラ の宣言を行います。

例 3.29. コンボ ボックス コントロール と ハンドラ の宣言

SFMTYPEDEFRESPONDER(MyWindow)
class MyWindow : public SFZWindow {
    SFMSEALRESPONDER(MyWindow)
    SFMRESPONDERINSTANTIATEFOUR(MyWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
public:
    enum CodeEnum {
        CODE_TYPE = four_char_code('M', 'W', 'N', 'D')
    };
    SFMTYPEDEFTYPE(CodeEnum)
private:
    SFZTextButtonControlSmp _button1;
    SFZTextButtonControlSmp _button2;
    SFZTextButtonControlSmp _button3;
    SFZCheckboxControlSmp _checkbox1;
    SFZCheckboxControlSmp _checkbox2;
    SFZRadiobuttonControlSmp _radio1;
    SFZRadiobuttonControlSmp _radio2;
    Bool _ifShowHw;

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

    // コンボ ボックス コントロールの宣言
    SFZComboBoxControlSmp _combobox;
public:
    static MyWindowSmp NewInstance(SFCErrorPtr exception = null);
    SFCError Make(Void);
protected:
    explicit MyWindow(Void) static_throws;
    virtual ~MyWindow(Void);

    virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const;
    XANDLER_DECLARE_BOOLEVENT(OnKey)
    XANDLER_DECLARE_VOIDRESULT(OnButton12)
    XANDLER_DECLARE_VOIDRESULT(OnButton3)
    XANDLER_DECLARE_VOIDRESULT(OnCheck)
    XANDLER_DECLARE_VOIDRESULT(OnRadio)

    // コンボ ボックス ハンドラの宣言
    XANDLER_DECLARE_VOIDRESULT(OnComboBox)
private:
    SFCError CreateButtons(SFXGridPtr offs);
    SFCError CreateCheckBoxes(SFXGridPtr offs);
    SFCError CreateRadioButtons(SFXGridPtr offs);

    // コンボ ボックスの作成
    SFCError CreateComboBox(SFXGridPtr offs);

};

コンボ ボックスが作成されるように MyWindow::Make() を変更します。

例 3.30. レスポンダの作成

// MyWindow 上のレスポンダ作成
SFCError MyWindow::Make(Void)
{
    SFCError error;

    SFXGrid offset(0, 0);

    offset.Add(X_MARGIN, Y_MARGIN);

    if ((error = CreateButtons(&offset)) != SFERR_NO_ERROR) {
        return error;
    }
    if ((error = CreateCheckBoxes(&offset)) != SFERR_NO_ERROR) {
        return error;
    }
    if ((error = CreateRadioButtons(&offset)) != SFERR_NO_ERROR) {
        return error;
    }

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

    // コンボ ボックスを作成します。
    if ((error = CreateComboBox(&offset)) != SFERR_NO_ERROR) {
        return error;
    }

    return error;
}

コンボ ボックスのインスタンス作成と初期化を行うコードを追加します。

コンボ ボックスの項目と属性をカスタマイズします。

例 3.31. コンボ ボックスのインスタンス作成 と 初期化

// コンボ ボックスの作成
SFCError MyWindow::CreateComboBox(SFXGridPtr offs)
{
    SFCError error;
    SFXGraphicsPtr graphics = SFXGraphics::GetInstance();
    SInt16Const height = graphics->GetFontHeight() + 4;
    SInt16Const width = (GetVirtualBound().GetWidth() - 2 * X_MARGIN);
    SFXRectangle rect(*offs, width, height);

    // コンボボックス
    // コンボ ボックスのインスタンスを作成します。
    if ((_combobox = SFZComboBoxControl::NewInstance(&error)) != null) {
        error = _combobox->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _combobox->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnComboBox)
            );
            if (error == SFERR_NO_ERROR) {

                // コンボ ボックスの項目を設定します。
                SFXAnsiString item[] = {"First", "Second", "Third"};
                for (int i = 0; i  sizeof(item) / sizeof(item[0]); ++i) {

                    // コンボ ボックスに項目を追加します。
                    error = _combobox->Append(item[i]);
                    if (error != SFERR_NO_ERROR) {
                        TRACE("item error");
                        break;
                    } else {
                        TRACE("no item error");
                    }
                }
                if (error == SFERR_NO_ERROR) {
                    _combobox->SetRealBound(rect);
                    _combobox->SetState(true, true, true, false);
                }
            }
        }
    }
    offs->AddY(rect.GetHeight() + Y_MARGIN);

    return error;
}

コンボ ボックスの項目番号が変更されたときに実行するハンドラを実装します。

コンボ ボックスの項目をデバッグ ウィンドウに表示します。

例 3.32. コンボ ボックス ハンドラの実装

// コンボ ボックス ハンドラの実装
XANDLER_IMPLEMENT_VOIDRESULT(MyWindow, OnComboBox, invoker, reason, result)
{
    unused(invoker);
    unused(reason);

    // result : 選択された項目番号
    SFXWideString string(_combobox->GetItemData(static_castSInt16(result)));

    // 選択された項目番号と項目をデバッグ表示します。
    TRACE("'%d: %S' is selected.", result, string.GetCString());

    return;
}
[Caution] 注意

コンボ ボックスの項目番号が変更されなかった場合、イベントは発生しません。

シミュレータでの実行結果です。

図 3.14. 実行結果

実行結果

図 3.15. コンボ ボックスの項目が選択されたときのデバッグ ウィンドウ ( 選択された項目が出力されます )

コンボ ボックスの項目が選択されたときのデバッグ ウィンドウ ( 選択された項目が出力されます )

3.3.5. テキスト ラベル と エディット ボックス (パスワード認証)

図のようにテキスト ラベルとエディット ボックスを配置するコードを追加します。

エディット ボックスに入力したパスワードの認証を行います。

図 3.16. テキスト ラベル と エディット ボックス

テキスト ラベル と エディット ボックス

テキスト ラベル コントロール と エディット ボックス コントロール 及び そのハンドラの宣言を行います。

例 3.33. テキスト ラベル コントロール と エディット ボックス コントロール 及び そのハンドラの宣言

SFMTYPEDEFRESPONDER(MyWindow)
class MyWindow : public SFZWindow {
    SFMSEALRESPONDER(MyWindow)
    SFMRESPONDERINSTANTIATEFOUR(MyWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
public:
    enum CodeEnum {
        CODE_TYPE = four_char_code('M', 'W', 'N', 'D')
    };
    SFMTYPEDEFTYPE(CodeEnum)
private:
    SFZTextButtonControlSmp _button1;
    SFZTextButtonControlSmp _button2;
    SFZTextButtonControlSmp _button3;
    SFZCheckboxControlSmp _checkbox1;
    SFZCheckboxControlSmp _checkbox2;
    SFZRadiobuttonControlSmp _radio1;
    SFZRadiobuttonControlSmp _radio2;
    Bool _ifShowHw;
    SFZComboBoxControlSmp _combobox;

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

    // テキスト ラベル コントロール と エディット ボックス コントロール の宣言
    SFZSingleTextLabelControlSmp _singleTextLabel;
    SFZSingleEditBoxControlSmp _singleEditBox;
private:
    SFCError CreateButtons(SFXGridPtr offs);
    SFCError CreateCheckBoxes(SFXGridPtr offs);
    SFCError CreateRadioButtons(SFXGridPtr offs);
    SFCError CreateComboBox(SFXGridPtr offs);

    // テキスト ラベルとエディット ボックスの作成
    SFCError CreatePassLine(SFXGridPtr offs);
public:
    static MyWindowSmp NewInstance(SFCErrorPtr exception = null);
    SFCError Make(Void);
protected:
    explicit MyWindow(Void) static_throws;
    virtual ~MyWindow(Void);

    virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const;
    XANDLER_DECLARE_BOOLEVENT(OnKey)
    XANDLER_DECLARE_VOIDRESULT(OnButton12)
    XANDLER_DECLARE_VOIDRESULT(OnButton3)
    XANDLER_DECLARE_VOIDRESULT(OnCheck)
    XANDLER_DECLARE_VOIDRESULT(OnRadio)
    XANDLER_DECLARE_VOIDRESULT(OnComboBox)

    // エディット ボックス ハンドラの宣言
    XANDLER_DECLARE_VOIDRESULT(OnSingleEditBox)
};

テキスト ラベル と エディット ボックスが作成されるように MyWindow::Make() を変更します。

例 3.34. レスポンダの作成

// MyWindow 上のレスポンダ作成
SFCError MyWindow::Make(Void)
{
    SFCError error;

    SFXGrid offset(0, 0);

    offset.Add(X_MARGIN, Y_MARGIN);

    if ((error = CreateButtons(&offset)) != SFERR_NO_ERROR) {
        return error;
    }
    if ((error = CreateCheckBoxes(&offset)) != SFERR_NO_ERROR) {
        return error;
    }
    if ((error = CreateRadioButtons(&offset)) != SFERR_NO_ERROR) {
        return error;
    }
    if ((error = CreateComboBox(&offset)) != SFERR_NO_ERROR) {
        return error;
    }

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

    // テキスト ラベルとエディット ボックスを作成します。
    if ((error = CreatePassLine(&offset)) != SFERR_NO_ERROR) {
        return error;
    }

    return error;
}

テキスト ラベルとエディット ボックスのインスタンス作成と初期化を行うコードを追加します。

エディット ボックスの最大文字長を10文字にし、入力した文字列を"****"にして見えないようにします。

また、テキスト ラベルにはカーソルを合わせないようにします。

例 3.35. // テキスト ラベルとエディットボックスのインスタンス作成 と 初期化

// テキスト ラベルとエディット ボックスの作成
SFCError MyWindow::CreatePassLine(SFXGridPtr offs)
{
    SFCError error;
    SFXRectangle rect;

    // テキスト ボックスの作成
    if ((_singleTextLabel = SFZSingleTextLabelControl::NewInstance(&error)) != null) {
        error = _singleTextLabel->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _singleTextLabel->SetText("PW:");
            if (error == SFERR_NO_ERROR) {

                // テキスト ボックスの最適なサイズを計算します。
                rect.Set(*offs, _singleTextLabel->GetSuitableBound().GetSize());
                _singleTextLabel->SetRealBound(rect);

                // 状態を選択不可にします。(visible, active, enable, focus)
                _singleTextLabel->SetState(true, true, false, false);
            }
        }
    }

    // エディット ボックスの作成
    if ((_singleEditBox = SFZSingleEditBoxControl::NewInstance(&error)) != null) {
        error = _singleEditBox->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _singleEditBox->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnSingleEditBox)
            );
            if (error == SFERR_NO_ERROR) {

                // パスワード モードに設定します。
                error = _singleEditBox->SetPasswordMode(true);
                if (error == SFERR_NO_ERROR) {

                    // 最大文字長を 10 文字にします。
                    error = _singleEditBox->SetMaximumLength(10);
                    if (error == SFERR_NO_ERROR) {

                        // 英数字のみの入力に限定します。
                        _singleEditBox->SetInputMode(AEE_TM_LETTERS | AEE_TM_NUMBERS);

                        // 左にテキストをアラインします。
                        _singleEditBox->SetHorizontalAlign(SFZSingleEditBoxControl::HORIZONTAL_LEFT);

                        rect.Offset(rect.GetWidth(), 0);
                        rect.SetRight(GetVirtualBound().GetWidth() - X_MARGIN);
                        _singleEditBox->SetRealBound(rect);
                        _singleEditBox->SetState(true, true, true, false);
                    }
                }
            }
        }
    }

    offs->AddY(rect.GetHeight() + Y_MARGIN);

    return error;
}

エディット ボックスの入力が変更されたときに実行するハンドラを追加します。

パスワードを認証して結果をデバッグ ウィンドウに表示します。

例 3.36. エディット ボックス - ハンドラの実装

// エディット ボックス ハンドラの実装
XANDLER_IMPLEMENT_VOIDRESULT(MyWindow, OnSingleEditBox, invoker, reason, result)
{
    unused(invoker);
    unused(reason);

    // 文字列を真のパスワードと比較します。
    if (_singleEditBox->GetText().Compare("pass") == 0) {
        TRACE("password: authenticated!");
    } else {
        TRACE("password: can't be authenticated...");
    }

    return;
}

シミュレータでの実行結果です。

図 3.17. 実行結果

実行結果

図 3.18. テキスト入力画面

テキスト入力画面

図 3.19. パスワードが入力されたときのデバッグ ウィンドウ ( 認証結果が出力されます )

パスワードが入力されたときのデバッグ ウィンドウ ( 認証結果が出力されます )

3.3.6. リスト ボックス

図のようにリスト ボックスを配置するコードを追加します。

リスト ボックスの内容とコンボ ボックスの内容を同期させるようにします。

図 3.20. リスト ボックス

リスト ボックス

リスト ボックス コントロール と そのハンドラの宣言を行います。

例 3.37. リスト ボックス コントロールとそのハンドラの宣言

SFMTYPEDEFRESPONDER(MyWindow)
class MyWindow : public SFZWindow {
    SFMSEALRESPONDER(MyWindow)
    SFMRESPONDERINSTANTIATEFOUR(MyWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
public:
    enum CodeEnum {
        CODE_TYPE = four_char_code('M', 'W', 'N', 'D')
    };
    SFMTYPEDEFTYPE(CodeEnum)
private:
    SFZTextButtonControlSmp _button1;
    SFZTextButtonControlSmp _button2;
    SFZTextButtonControlSmp _button3;
    SFZCheckboxControlSmp _checkbox1;
    SFZCheckboxControlSmp _checkbox2;
    SFZRadiobuttonControlSmp _radio1;
    SFZRadiobuttonControlSmp _radio2;
    Bool _ifShowHw;
    SFZComboBoxControlSmp _combobox;
    SFZSingleTextLabelControlSmp _singleTextLabel;
    SFZSingleEditBoxControlSmp _singleEditBox;

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

    // リスト ボックス コントロール の宣言
    SFZListBoxControlSmp _listbox;
private:
    SFCError CreateButtons(SFXGridPtr offs);
    SFCError CreateCheckBoxes(SFXGridPtr offs);
    SFCError CreateRadioButtons(SFXGridPtr offs);
    SFCError CreateComboBox(SFXGridPtr offs);
    SFCError CreatePassLine(SFXGridPtr offs);

    // リスト ボックスの作成
    SFCError CreateListBox(SFXGridPtr offs);
public:
    static MyWindowSmp NewInstance(SFCErrorPtr exception = null);
    SFCError Make(Void);

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

    virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const;
    XANDLER_DECLARE_BOOLEVENT(OnKey)
    XANDLER_DECLARE_VOIDRESULT(OnButton12)
    XANDLER_DECLARE_VOIDRESULT(OnButton3)
    XANDLER_DECLARE_VOIDRESULT(OnCheck)
    XANDLER_DECLARE_VOIDRESULT(OnRadio)
    XANDLER_DECLARE_VOIDRESULT(OnComboBox)
    XANDLER_DECLARE_VOIDRESULT(OnSingleEditBox)

    // リスト ボックス ハンドラの宣言
    XANDLER_DECLARE_VOIDRESULT(OnListBox)
};

リスト ボックスが作成されるように MyWindow::Make() を変更します。

例 3.38. レスポンダの作成

// MyWindow 上のレスポンダの作成
SFCError MyWindow::Make(Void)
{
    SFCError error;
    SFXGrid offset(0, 0);
    offset.Add(X_MARGIN, Y_MARGIN);

    if ((error = CreateButtons(&offset)) != SFERR_NO_ERROR) {
        TRACE("button error");
        return error;
    }
    if ((error = CreateCheckBoxes(&offset)) != SFERR_NO_ERROR) {
        TRACE("check box error");
        return error;
    }
    if ((error = CreateRadioButtons(&offset)) != SFERR_NO_ERROR) {
        TRACE("radio button error");
        return error;
    }
    if ((error = CreateComboBox(&offset)) != SFERR_NO_ERROR) {
        TRACE("combo error");
        return error;
    }
    if ((error = CreatePassLine(&offset)) != SFERR_NO_ERROR) {
        return error;
    }

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

    // リスト ボックスを作成します。
    if ((error = CreateListBox(&offset)) != SFERR_NO_ERROR) {
        return error;
    }

    return error;
}

リスト ボックスのインスタンス作成と初期化を行うコードを追加します。

リスト ボックスの項目と属性をカスタマイズします。

例 3.39. リスト ボックスのインスタンス作成と初期化

// リスト ボックスの作成
SFCError MyWindow::CreateListBox(SFXGridPtr offs)
{
    SFCError error;
    SFXGraphicsPtr graphics = SFXGraphics::GetInstance();
    SInt16Const width = (GetVirtualBound().GetWidth() - 2 * X_MARGIN);
    SFXRectangle rect(*offs, width, 0);

    // リスト ボックスのインスタンスを作成します。
    if ((_listbox = SFZListBoxControl::NewInstance(&error)) != null) {
        error = _listbox->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _listbox->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnListBox)
            );
            if (error == SFERR_NO_ERROR) {

                // 表示する項目を追加します。
                SFXAnsiString item[] = {"First", "Second", "Third"};

                // (項目の高さ) × (項目の数) 分の高さを割り当てます
                rect.SetHeight(_listbox->GetItemHeight() * lengthof(item));
                _listbox->SetRealBound(rect);

                for (int i = 0; i < lengthof(item); ++i) {
                    error = _listbox->Append(item[i]);
                    if (error != SFERR_NO_ERROR) {
                        break;
                    }
                }
                if (error == SFERR_NO_ERROR) {

                    // リストボックス内での UP キーを LEFT キーに設定します。
                    _listbox->SetUpKey(AVK_LEFT);

                    // リストボックス内での DOWN キーを RIGHT キーに設定します。
                    _listbox->SetDownKey(AVK_RIGHT);

                    _listbox->SetState(true, true, true, false);
                }
            }
        }
    }
    offs->AddY(rect.GetHeight() + Y_MARGIN);

    return error;
}
[Note] 自動スクロール バー

全項目を一度に表示しきれない場合、リスト ボックスでも自動的にスクロール バーが追加されます。

[Caution] SetUpKey() と SetDownKey() について

リスト ボックスのデフォルトで設定されている UP キーや DOWN キーは、そのまま携帯の UP キーと DOWN キーに割り当てられています。

フォーカス移動ができない場合はキーを適切に設定する必要があります。

リスト ボックスの項目番号が変更されたときに実行するハンドラを実装します。

リスト ボックスの項目をデバッグ ウィンドウに表示します。

コンボ ボックスの項目番号と同期するため、コンボ ボックス ハンドラも変更します。

例 3.40. リスト ボックス ハンドラの実装 と コンボ ボックス ハンドラの変更

// リスト ボックス ハンドラ
XANDLER_IMPLEMENT_VOIDRESULT(MyWindow, OnListBox, invoker, reason, result)
{
    unused(invoker);
    unused(reason);

    // result : 選択された項目番号
    SFXWideString string(_listbox->GetItemText(static_cast<SInt16>(result)));

    // 選択された項目番号と項目をデバッグ表示します。
    TRACE("%d: %S is selected.", result, string.GetCString());

    // コンボ ボックスの値と同期します。
    _combobox->SetValue(result);

    return;
}

// コンボ ボックス ハンドラ
XANDLER_IMPLEMENT_VOIDRESULT(MyWindow, OnComboBox, invoker, reason, result)
{
    unused(invoker);
    unused(reason);

    // result : 選択された項目番号
    SFXWideString string(_combobox->GetItemData(static_castSInt16(result)));

    // 選択された項目番号と項目をデバッグ表示します。
    TRACE("%d: %S is selected.", result, string.GetCString());

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

    // リスト ボックスの値と同期します。
    _listbox->SetValue(result);

    return;
}

シミュレータでの実行結果です。

図 3.21. 実行結果

実行結果

図 3.22. リスト ボックスの項目が選択されたときのデバッグ ウィンドウ

リスト ボックスの項目が選択されたときのデバッグ ウィンドウ