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

3.5. タブ コントロール

3.5.1. タブ コントロール と タブ ページ

タブ コントロールは、タブ形式での入出力を可能にしてくれるコントロールです。

タブ コントロール内のそれぞれのタブは、タブ ページによって管理されます。

前節で作成した MyWindow と MenuWindow を図のようにタブで管理します。

基本的にはタブ ページの子レスポンダとして登録すれば、そのまま利用できます。

図 3.27. タブ コントロール と タブ ページ

タブ コントロール と タブ ページ

タブ コントロールを配置するウィンドウを定義します。

例 3.45. タブ コントロール ウィンドウの宣言

// タブ コントロールを配置するウィンドウの宣言
SFMTYPEDEFRESPONDER(TabWindow)
class TabWindow : public SFZWindow {
    SFMSEALRESPONDER(TabWindow)
    SFMRESPONDERINSTANTIATEFOUR(TabWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
public:
    // このレスポンダのタイプを定義します。
    // 小文字と記号からのみなるタイプはSophiaFramework により予約されています。
    enum CodeEnum {
        CODE_TYPE = four_char_code('T', 'A', 'B', 'W')
    };
    SFMTYPEDEFTYPE(CodeEnum)
private:
    // タブ コントロールの宣言
    SFZTabControlSmp _tab;
    // タブ ページの子レスポンダ
    MyWindowSmp _myWindow;
    MenuWindowSmp _menuWindow;
public:
    static TabWindowSmp NewInstance(SFCErrorPtr exception = null);
    SFCError Make();
protected:
    explicit TabWindow(Void) static_throws;
    virtual ~TabWindow(Void);

    virtual Void HandleRenderRequest(SFXGraphicsPtr graphics) const;
    // キー ハンドラ
    XANDLER_DECLARE_BOOLEVENT(OnTabKey)
};

タブ コントロール ウィンドウの定義

例 3.46. タブ コントロール ウィンドウの実装

// コンストラクタ
TabWindow::TabWindow(Void) static_throws
{
    if (static_try()) {
        // このレスポンダのタイプを設定します。
        SetType(CODE_TYPE);
    }
}

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

// インスタンス作成
TabWindowSmp TabWindow::NewInstance(SFCErrorPtr exception)
{
    return static_pointer_cast<TabWindow>(Factory(:: new TabWindow, exception));
}

// レスポンダ作成
SFCError TabWindow::Make()
{
    SFCError error;

    // タブ コントロールのインスタンスを作成します。
    if ((_tab = SFZTabControl::NewInstance(&error)) != null) {
        error = _tab->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            // タブ コントロールに キーハンドラを登録します。
            error = _tab->RegisterHandler(
                SFXEventRange(SFEVT_KEY, SFEVT_KEY, SFP16_BEGIN, SFP16_END),
                XANDLER_INTERNAL(OnTabKey)
            );
            if (error == SFERR_NO_ERROR) {
                _tab->SetRealBound(GetLocalBound());

                // タブ コントロールの各色を設定します。
                _tab->SetBackgroundColor(COLOR_TAB);
                _tab->SetArrowColor(COLOR_BLACK);
                SFXBevelColor tabBevel(COLOR_LIGHT_PURPLE, COLOR_DEEP_PURPLE, COLOR_BLACK);
                _tab->SetTabBevelColor(tabBevel);

                // タブ コントロールの境界線を描画するように設定します。
                _tab->SetDrawBorder(true);

                // タブの切り替えをそれぞれ SOFT 1 キー と SOFT 2 キーに設定します。
                _tab->SetFocusLeftKey(AVK_SOFT1);
                _tab->SetFocusRightKey(AVK_SOFT2);

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

                // 1 つ目のタブ ページのインスタンスを作成します。
                SFZTabPageSmp page1 = SFZTabPage::NewInstance(&error);
                if (page1 != null) {

                    // ページのタイトルを設定します。(タブ部分に表示されます。)
                    page1->SetTitle("Controls");

                    // ページのヒントを設定します。
                    error = page1->SetHint("This is MyWindow.");
                    if (error == SFERR_NO_ERROR) {

                        // タブ コントロールに作成したタブ ページを挿入します。
                        // 内部的にはタブ コントロールの子レスポンダとして登録されます。
                        _tab->Insert(page1);

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

                            // MyWindowの親レスポンダを 1つ目のタブ ページに設定します。
                            error = _myWindow->SetParent(page1);
                            if (error == SFERR_NO_ERROR) {
                                _myWindow->SetBackgroundColor(COLOR_LIGHT_GREEN);
                                SFXRectangle rect = page1->GetLocalBound();

                                // ページ全体分の領域を MyWindow に割り当てます。
                                _myWindow->SetRealBound(rect);

                                // タブ の分だけ領域が狭くなるので、十分表示しきれない場合を考慮して、
                                // 仮想領域を実領域より下に高さ 100 分だけ大きめに設定しています。
                                _myWindow->SetVirtualBound(rect.SnapLeftTop(0, 0).AddBottom(100));

                                _myWindow->SetState(true, true, true, true);
                                _myWindow->ToFront();
                                _myWindow->Make();
                            }
                        }
                    }
                }
                if (error == SFERR_NO_ERROR) {
                    // 2 つ目のタブ ページのインスタンスを作成します。
                    // 2 つ目のタブ ページには MenuWindow を登録します。
                    SFZTabPageSmp page2 = SFZTabPage::NewInstance(&error);
                    if (page2 != null) {
                        page2->SetTitle("TextMenu");
                        error = page2->SetHint("This is MenuWindow.");
                        if (error != SFERR_NO_ERROR) {
                            _tab->Insert(page2);
                            if ((_menuWindow = MenuWindow::NewInstance(&error)) != null) {
                                error = _menuWindow->SetParent(page2);
                                if (error == SFERR_NO_ERROR) {
                                    _menuWindow->SetBackgroundColor(COLOR_DEEP_PURPLE);
                                    SFXRectangle rect = page2->GetLocalBound();
                                    _menuWindow->SetRealBound(rect);
                                    _menuWindow->SetState(true, true, true, true);
                                    _menuWindow->ToFront();
                                    _menuWindow->Make();
                                }
                            }
                        }
                    }
                }
                if (error == SFERR_NO_ERROR) {
                    // 画面に 2 つのタブ ページが表示されるように設定します。
                    _tab->SetTabsNumber(2);
                    page1->ToFront();
                }
            }
        }
    }

    return error;
}

// ウィンドウの描画ハンドラ
Void TabWindow::HandleRenderRequest(SFXGraphicsPtr graphics) const
{
    unused(graphics);

    return;
}

// タブ キー ハンドラ
XANDLER_IMPLEMENT_BOOLEVENT(TabWindow, OnTabKey, invoker, event)
{
    switch (event.GetP16()) {
        case AVK_SOFT3:
            // SOFT 3 キーでタブ ウィンドウを終了します。
            this->Terminate();
            return true;
        default:
            break;
    }
    return false;
}

Hello World 画面で 3 キーを押すとタブ コントロール ウィンドウを表示するようにします。

SOFT 3 キーを押すと、タブ ウィンドウは閉じます。

例 3.47. HelloWorld クラスの変更

// HelloWorld クラスの宣言
SFMTYPEDEFCLASS(HelloWorld)
class HelloWorld : public SFYApplication {
    SFMSEALCOPY(HelloWorld)
private:
    MyWindowSmp _myWindow;
    MenuWindowSmp _menuWindow;

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

    // TabWindow のスマートポインタ
    TabWindowSmp _tabWindow;
public:
    static SFCInvokerPtr Factory(Void);
private:
    explicit HelloWorld(Void) static_throws;
    virtual ~HelloWorld(Void);
    SFCError MakeMy(Void);
    SFCError MakeMenu(Void);
    // TabWindow 作成
    SFCError MakeTab(Void);
    XANDLER_DECLARE_VOIDRENDER(OnRenderRequest)
    XANDLER_DECLARE_BOOLEVENT(OnKey)
};

// TabWindow の作成
SFCError HelloWorld::MakeTab(Void)
{
    SFCError error(SFERR_NO_ERROR);

    if ((_tabWindow = TabWindow::NewInstance(&error)) != null) {
        error = _tabWindow->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {
            _tabWindow->SetRealBound(_tabWindow->GetSuitableBound(GetLocalBound()));
            _tabWindow->SetState(true, true, true, true);
            // ウィンドウを最前面に移動します。
            _tabWindow->ToFront();
            _tabWindow->Make();
        }
    }

    return error;
}

// 描画ハンドラ
XANDLER_IMPLEMENT_VOIDRENDER(HelloWorld, OnRenderRequest, invoker, reason, graphics)
{
    unused(invoker);

    graphics->FillRectangle(GetGlobalBound(), COLOR_WHITE);

    graphics->DrawSingleText("1key - Controls", SFXGrid(20, 20), GetGlobalBound(), COLOR_BLACK);
    graphics->DrawSingleText("2key - TextMenu", SFXGrid(20, 40), GetGlobalBound(), COLOR_BLACK);
    graphics->DrawSingleText("3key - TabControl", SFXGrid(20, 60), GetGlobalBound(), COLOR_BLACK);

    return;
}

// キー ハンドラ
XANDLER_IMPLEMENT_BOOLEVENT(HelloWorld, OnKey, invoker, event)
{
    unused(invoker);

    // キー ハンドラの処理
    switch (event.GetP16()) {
        case AVK_SELECT:
            Terminate();
            return true;
        case AVK_1:
         TRACE("1 key");
            if (MakeMy() != SFERR_NO_ERROR) { 
                return false;
            }
            return true;
        case AVK_2:
            TRACE("2 key");
            if (MakeMenu() != SFERR_NO_ERROR) {
                return false;
            }
            return true;
        case AVK_3:
            TRACE("3 key");
            if (MakeTab() != SFERR_NO_ERROR) {
                return false;
            }
            return true;
    }
    return false;
}

MyWindow クラスと MenuWindow クラスはクリア キーで終了します。

タブ ページ内でクリア キーを押すと、空白のページだけが残ってしまいます。

そこで、親レスポンダがタブ ページの場合はクリア キーで終了しないように変更します。

例 3.48. クリア キー ガード

// MyWindow キー ハンドラ
XANDLER_IMPLEMENT_BOOLEVENT(MyWindow, OnKey, invoker, event)
{
    switch (event.GetP16()) {
        case AVK_1:
        case AVK_2:
        case AVK_3:
            return true;
        case AVK_CLR: // クリアー キーが押された時
            {
                SFYResponderSmp resp = invoker->GetParent();

                // 親レスポンダがタブ ページでないときのみウィンドウを閉じます。
                if (resp != null && resp->GetType() != four_char_code('p', 't', 'a', 'b')) {
                    TRACE("MyWindow's parent is a tabpage");
                }
                else {
                    invoker->Terminate();
                }
            }
            return true;
    }

    return false;
}

// MenuWindow - SFZTextMenu の結果ハンドラ
XANDLER_IMPLEMENT_VOIDRESULT(MenuWindow, OnMenuResult, invoker, reason, result)
{
    if (reason == SFP16_RESULT_OK) {
        TRACE("%S selected", static_cast<SFZTextMenuPtr>(invoker)->GetItemText((SInt16)result).GetCString());
        switch (result) {
            ・・・省略・・・
        }
    }
    else {
        SFYResponderSmp resp = this->GetParent();
        if (resp != null && resp->GetType() == four_char_code('p', 't', 'a', 'b')) {
            TRACE("MenuWindow's parent is a tabpage.");
        }
        else {
            this->Terminate();
        }
    }
    return;
}

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

  1. 3 キーを押すと、タブ コントロール ウィンドウが表示されます。
  2. SOFT 1 キーと SOFT 2 キーでタブを切り替えます。
  3. SOFT 3 キーでタブ コントロール ウィンドウを閉じます。

図 3.28. 初期 ウィンドウ (HelloWorld)

初期 ウィンドウ (HelloWorld)

図 3.29. タブ コントロール ウィンドウ (ページ 1)

タブ コントロール ウィンドウ (ページ 1)

図 3.30. タブ コントロール ウィンドウ (ページ 2)

タブ コントロール ウィンドウ (ページ 2)