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

9.17. コントロール(応用編)

複数のコントロールを同時に使用する方法や、コントロール同士の連携などについて解説します。

9.17.1. フォーカスの色を変更する

図 9.65. 動作例

動作例

各種コントロールでは、フォーカス状態の場合に描画されるフォーカスの色を変更できます。

フォーカスを目立たせたい場合やインターフェース全体の色を変更する場合などに利用できます。

例 9.125. 宣言

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow : public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZTextButtonControlSmp _button;

    ...
private:
    SFCError Make(Void);
};

例 9.126. 実装

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

    if ((_button = SFZTextButtonControl::NewInstance(&error)) != null) {
        error = _button->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _button->SetText("hello world");
            if (error == SFERR_NO_ERROR) {

                // デフォルトのフォーカス色を取得し、赤色を加算して設定する
                _button->SetFocusColor(SFXBevelColor(_button->GetFocusColor()).AddRed(0xFF));

                _button->SetRealBound(_button->GetSuitableBound().SetOrigin(10, 10));
                _button->SetState(true, true, true, true);
            }
        }
    }
    return error;
}

9.17.2. コントロールの色を変更する

図 9.66. 動作例

動作例

各種コントロールでは、フォーカスの色に加え、コントロールの各個所の色を変更できます。

変更できる個所は、コントロールの種類や実装に依存します。

例 9.127. 宣言

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow : public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZTextButtonControlSmp _button;

    ...
private:
    SFCError Make(Void);
};

例 9.128. 実装

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

    if ((_button = SFZTextButtonControl::NewInstance(&error)) != null) {
        error = _button->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _button->SetText("hello world");
            if (error == SFERR_NO_ERROR) {

                // デフォルトのフォーカス色を取得し、赤色と緑色を減算して設定する
                _button->SetFocusColor(SFXBevelColor(_button->GetFocusColor()).SubRGB(0x33, 0x33, 0x00));

                // デフォルトのボタン色を取得し、赤色と緑色を減算して設定する
                _button->SetButtonColor(SFXBevelColor(_button->GetButtonColor()).SubRGB(0x33, 0x33, 0x00));

                _button->SetRealBound(_button->GetSuitableBound().SetOrigin(10, 10));
                _button->SetState(true, true, true, true);
            }
        }
    }
    return error;
}

9.17.3. 複数行のテキスト コントロールに最適な大きさを取得する

図 9.67. 動作例

動作例

SFZMultipleTextLabelControl クラスや SFZMultipleTextBoxControl クラスなどの複数行のテキストを表示するコントロールでは、SFYResponder::GetSuitableBound 関数のうち、引数の矩形を指定しない関数が例外的な動作を行います。

これらのクラスでは複数行のテキストを表示するために、高さまたは幅のどちらかを固定しなければ最適な大きさを求められません。そこで、設定されている実領域の幅をヒント値として利用し最適な大きさを計算します。

引数を指定する関数では通常の動作を行い、実領域をあらかじめ設定する必要はありません。

引数を指定する関数と指定しない関数では、指定した矩形で高さを制限するかしないかの違いがあります。

例 9.129. 宣言

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow : public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZMultipleTextLabelControlSmp _label;

    ...
private:
    SFCError Make(Void);
};

例 9.130. 実装

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

    if ((_label = SFZMultipleTextLabelControl::NewInstance(&error)) != null) {
        error = _label->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _label->SetText("hello world\n\n"
                                    "0          \n"
                                    " 1         \n"
                                    "  2        \n"
                                    "   3       \n"
                                    "    4      \n"
                                    "     5     \n"
                                    "      6    \n"
                                    "       7   \n"
                                    "        8  \n"
                                    "         9 \n"
                                    "          0");
            if (error == SFERR_NO_ERROR) {

                // ヒント値を設定する
                _label->SetRealBound(GetLocalBound().Deflate(10, 10));

                // 矩形を指定せずに最適な大きさを取得して設定する
                _label->SetRealBound(_label->GetSuitableBound().SetOrigin(10, 10));

                _label->SetState(true, true, true, true);
            }
        }
    }
    return error;
}

9.17.4. 複数のコントロールを連続して配置する

図 9.68. 動作例

動作例

1つのコンテナ内に複数のコントロールを配置する場合、SFYResponder::GetSuitableBound 関数を利用することで見栄えのよいインターフェースを作成できます。

例 9.131. 宣言

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow : public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZTextButtonControlSmp _button;
    SFZSingleTextBoxControlSmp _box;
    SFZCheckboxControlSmp _checkbox;

    ...
private:
    SFCError Make(Void);
};

例 9.132. 実装

SFCError USRWindow::Make(Void)
{
    SFXRectangle rectangle;
    SFCError error(SFERR_NO_ERROR);

    // 1つ目のコントロールの左上の座標を設定する
    rectangle.Set(GetLocalBound().Deflate(10, 10));

    // 1つ目のコントロールを作成する
    if ((_button = SFZTextButtonControl::NewInstance(&error)) != null) {
        error = _button->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            error = _button->SetText("first");
            if (error == SFERR_NO_ERROR) {
                _button->SetRealBound(_button->GetSuitableBound(rectangle));
                _button->SetState(true, true, true, true);

                // 2つ目のコントロールの左上の座標を計算する
                rectangle.AddY(_button->GetRealBound().GetHeight() + 5);

                // 2つ目のコントロールを作成する
                if ((_box = SFZSingleTextBoxControl::NewInstance(&error)) != null) {
                    error = _box->SetParent(GetThis());
                    if (error == SFERR_NO_ERROR) {
                        error = _box->SetText("second");
                        if (error == SFERR_NO_ERROR) {
                            _box->SetRealBound(_box->GetSuitableBound(rectangle));
                            _box->SetState(true, true, true, false);

                            // 3つ目のコントロールの左上の座標を計算する
                            rectangle.AddY(_box->GetRealBound().GetHeight() + 5);

                            // 3つ目のコントロールを作成する
                            if ((_checkbox = SFZCheckboxControl::NewInstance(&error)) != null) {
                                error = _checkbox->SetParent(GetThis());
                                if (error == SFERR_NO_ERROR) {
                                    error = _checkbox->SetText("third");
                                    if (error == SFERR_NO_ERROR) {
                                        _checkbox->SetRealBound(_checkbox->GetSuitableBound(rectangle));
                                        _checkbox->SetState(true, true, true, false);

                                        // 4つ目のコントロールの左上の座標を計算する
                                        rectangle.AddY(_checkbox->GetRealBound().GetHeight() + 5);
                                        ...
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return error;
}

9.17.5. ラジオボタンコントロールをグループ化する

図 9.69. 動作例

動作例

複数のラジオボタンコントロールをグループ化することで、排他的なチェック状態の切り替えを自動的に行うことができます。

自動的な排他処理はユーザーのキー操作によってのみ行われ、SFYControl::SetCurrentValue 関数を利用してチェック状態を切り替える場合には行われません。

例 9.133. 宣言

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow : public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZRadiobuttonControlSmp _radiobutton[5];

    ...
private:
    SFCError Make(Void);
};

例 9.134. 実装

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

    rectangle.Set(GetLocalBound().Deflate(10, 10));

    // ラジオボタンコントロールをまとめて作成する
    for (i = 0; i < 5 & error == SFERR_NO_ERROR; ++i) {
        if ((_radiobutton[i] = SFZRadiobuttonControl::NewInstance(&error)) != null) {
            error = _radiobutton[i]->SetParent(GetThis());
            if (error == SFERR_NO_ERROR) {
                error = _radiobutton[i]->SetText(SFXWideString::Format("number %d", i));
                if (error == SFERR_NO_ERROR) {
                    _radiobutton[i]->SetRealBound(_radiobutton[i]->GetSuitableBound(rectangle));
                    _radiobutton[i]->SetState(true, true, true, false);
                    rectangle.AddY(_radiobutton[i]->GetRealBound().GetHeight() + 5);
                }
            }
        }
    }
    if (error == SFERR_NO_ERROR) {

        // すべてのラジオボタンコントロールをグループ化する
        for (i = 1; i < 5; ++i) {
            _radiobutton[i]->Group(_radiobutton[0]);
        }

        // 1つ目をチェックされている状態に設定する
        _radiobutton[0]->SetCurrentValue(true);

        // 1つ目にフォーカスを移動する
        _radiobutton[0]->SetStateFocus(true);
    }
    return error;
}

9.17.6. チェックボックスコントロールの状態に応じて活性状態を切り替える

図 9.70. 動作例

動作例

チェックボックスコントロールの状態に応じて、関連するコントロールの活性状態を切り替えるとユーザービリティのよいインターフェースを作成できます。

例 9.135. 宣言

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow : public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZCheckboxControlSmp _checkbox[2];
    SFZRadiobuttonControlSmp _radiobutton[3];
    SFZSingleEditBoxControlSmp _editbox;

    ...
private:
    SFCError Make(Void);
    SFCError Init(SFYResponderSmpConstRef responder, SFXRectanglePtr rectangle);

    // 1つ目のチェックボックスコントロールのチェック変更イベントを処理するハンドラ
    XANDLER_DECLARE_VOIDVALUE(OnValue0)

    // 2つ目のチェックボックスコントロールのチェック変更イベントを処理するハンドラ
    XANDLER_DECLARE_VOIDVALUE(OnValue1)
};

例 9.136. 実装

SFCError USRWindow::Make(Void)
{
    static ACharConst item[][8] = {
        "Unix", "Mac", "Windows"
    };
    SFXRectangle rectangle;
    SInt16 i;
    SFCError error(SFERR_NO_ERROR);

    rectangle.Set(GetLocalBound().Deflate(10, 10));
    if ((_checkbox[0] = SFZCheckboxControl::NewInstance(&error)) != null) {

        // チェックボックスコントロールのチェック変更イベントを処理するハンドラを登録する
        error = _checkbox[0]->RegisterHandler(
            SFXEventRange(SFEVT_RESPONDER_VALUE, SFEVT_RESPONDER_VALUE, SFP16_VALUE_CURRENT, SFP16_VALUE_CURRENT),
            XANDLER_INTERNAL(OnValue0)
        );
        if (error == SFERR_NO_ERROR) {
            error = _checkbox[0]->SetText("Use linebreak");
            if (error == SFERR_NO_ERROR) {
                error = Init(_checkbox[0], &rectangle);
                if (error == SFERR_NO_ERROR) {
                    rectangle.AddLeft(10);
                    for (i = 0; i < 3 & error == SFERR_NO_ERROR; ++i) {
                        if ((_radiobutton[i] = SFZRadiobuttonControl::NewInstance(&error)) != null) {
                            error = _radiobutton[i]->SetText(item[i]);
                            if (error == SFERR_NO_ERROR) {
                                error = Init(_radiobutton[i], &rectangle);
                            }
                        }
                    }
                    for (i = 1; i < 3 & error == SFERR_NO_ERROR; ++i) {
                        _radiobutton[i]->Group(_radiobutton[0]);
                    }
                    rectangle.SubLeft(10);
                }
            }
        }
    }
    if (error == SFERR_NO_ERROR) {
        if ((_checkbox[1] = SFZCheckboxControl::NewInstance(&error)) != null) {

            // チェックボックスコントロールのチェック変更イベントを処理するハンドラを登録する
            error = _checkbox[1]->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_VALUE, SFEVT_RESPONDER_VALUE, SFP16_VALUE_CURRENT, SFP16_VALUE_CURRENT),
                XANDLER_INTERNAL(OnValue1)
            );
            if (error == SFERR_NO_ERROR) {
                error = _checkbox[1]->SetText("Use suffix");
                if (error == SFERR_NO_ERROR) {
                    error = Init(_checkbox[1], &rectangle);
                    if (error == SFERR_NO_ERROR) {
                        rectangle.AddLeft(10);
                        if ((_editbox = SFZSingleEditBoxControl::NewInstance(&error)) != null) {
                            error = _editbox->SetText(".txt");
                            if (error == SFERR_NO_ERROR) {
                                error = Init(_editbox, &rectangle);
                            }
                        }
                        rectangle.SubLeft(10);
                    }
                }
            }
        }
    }
    if (error == SFERR_NO_ERROR) {

        // 初期状態を調整する
        _checkbox[0]->SetCurrentValue(true);
        _radiobutton[0]->SetCurrentValue(true);
        _checkbox[1]->SetCurrentValue(true);
        _checkbox[0]->SetStateFocus(true);
    }
    return error;
}

SFCError USRWindow::Init(SFYResponderSmpConstRef responder, SFXRectanglePtr rectangle)
{
    SFCError error(SFERR_NO_ERROR);

    error = responder->SetParent(GetThis());
    if (error == SFERR_NO_ERROR) {
        responder->SetRealBound(responder->GetSuitableBound(*rectangle));
        responder->SetState(true, true, true, false);
        rectangle->AddY(responder->GetRealBound().GetHeight() + 5);
    }
    return error;
}

XANDLER_IMPLEMENT_VOIDVALUE(USRWindow, OnValue0, invoker, reason, value)
{
    SInt16 i;

    // チェックボックスコントロールの状態に応じて、
    // 活性状態を切り替える
    for (i = 0; i < 3; ++i) {
        _radiobutton[i]->SetStateActive(value != 0);
    }
    return;
}

XANDLER_IMPLEMENT_VOIDVALUE(USRWindow, OnValue1, invoker, reason, value)
{
    // チェックボックスコントロールの状態に応じて、
    // 活性状態を切り替える
    _editbox->SetStateActive(value != 0);
    return;
}