SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

ATL/WTLを利用したVisual C++のWindowsプログラミング

ATL/WTLプログラミング 6:ズームスクロールウィンドウ

ATL/WTLを利用したVisual C++のWindowsプログラミング

ペインコンテナ

 ペインコンテナとは、Explorerの左ペインのような外観を持つ、ビューウィンドウのコンテナのことです。ペインコンテナにの上部にはタイトル文字列を設定することができ、右上にはペインコンテナウィンドウを閉じるためのボタンが付いています。WTLはペインコンテナを作成するためにCPaneContainerを用意しています。

ペインコンテナ
ペインコンテナ

 次に示すのは、先ほどマルチペインステータスバーを追加したプログラムの左ペインに、ペインコンテナを適用した例です。変更するのはCMainFrame内です。

mainfrm.h
class CMainFrame : public CFrameWindowImpl<CMainFrame>,
        public CUpdateUI<CMainFrame>,
        public CMessageFilter, public CIdleHandler
{
public:
    DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)

    CSplitterWindow  m_wndSplitter;      // スプリッタウィンドウ
    CPaneContainer m_painContainer;      // ペインコンテナ
    CFontListView m_viewFontList;        // 左ペイン
    CFontPreviewView m_viewFontPreview;  // 右ペイン

    CCommandBarCtrl m_CmdBar;                // コマンドバー
    CMultiPaneStatusBarCtrl m_wndStatusBar;  // マルチステータスバー

    virtual BOOL PreTranslateMessage(MSG* pMsg){
        if(CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg))
            return TRUE;

        // 左ペインのPreTranslateMessageを呼び出す
        if(m_viewFontList.PreTranslateMessage(pMsg))
            return TRUE;

        // 右ペインのPreTranslateMessageを呼び出す
        return m_viewFontPreview.PreTranslateMessage(pMsg);
    }

    virtual BOOL OnIdle(){
        UIUpdateToolBar();
        UIUpdateStatusBar();

        CString strCount;
        strCount.Format(_T("フォント数:%d"), m_viewFontList.GetCount());
        m_wndStatusBar.SetPaneText(IDS_PANE_COUNT, strCount);

        return FALSE;
    }

    BEGIN_UPDATE_UI_MAP(CMainFrame)
        UPDATE_ELEMENT(ID_MENUITEM_CHANGEVIEW, UPDUI_MENUPOPUP |
 UPDUI_TOOLBAR)
    END_UPDATE_UI_MAP()

    BEGIN_MSG_MAP_EX(CMainFrame)
        MSG_WM_CREATE(OnCreate)
        COMMAND_CODE_HANDLER_EX(LBN_SELCHANGE, OnListSelChange)
        COMMAND_ID_HANDLER_EX(ID_PANE_CLOSE, OnMenuChangeView)
        COMMAND_ID_HANDLER_EX(ID_MENUITEM_CHANGEVIEW, OnMenuChangeView)
        COMMAND_ID_HANDLER_EX(ID_APP_EXIT, OnFileExit)
        CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
        CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
    END_MSG_MAP()

    LRESULT OnCreate(LPCREATESTRUCT lpcs){
        // コマンドバーを作成
        HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL,
            ATL_SIMPLE_CMDBAR_PANE_STYLE);

        // コマンドバーに現在のメニューバーのアイテムと画像をセット
        m_CmdBar.AttachMenu(GetMenu());
        m_CmdBar.LoadImages(IDR_MAINFRAME);

        // メニューバーを削除
        SetMenu(NULL);

        // ツールバーを作成
        HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd,
            IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);

        // リバーを作成
        CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);

        // リバーのバンドにコマンドバーとツールバーを追加
        AddSimpleReBarBand(hWndCmdBar);
        AddSimpleReBarBand(hWndToolBar, NULL, TRUE);

        // ステータスバーを作成
        m_hWndStatusBar = m_wndStatusBar.Create(m_hWnd);
        int nPanes[] = {ID_DEFAULT_PANE, IDS_PANE_COUNT};
        m_wndStatusBar.SetPanes(nPanes, sizeof(nPanes)/sizeof(nPanes[0]));

        UIAddToolBar(hWndToolBar);
        UIAddStatusBar(m_hWndStatusBar);

        UISetCheck(ID_MENUITEM_CHANGEVIEW, 1);

        // スプリッタウィンドウを作成
        m_wndSplitter.Create(m_hWnd, rcDefault, NULL,
            WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);

        // スプリッタウィンドウ拡張スタイルを設定
        m_wndSplitter.SetSplitterExtendedStyle(0);

        // ペインコンテナを作成
        m_painContainer.Create(m_wndSplitter, _T("フォント名"));

        // 左ペインのビューウィンドウを作成
        m_viewFontList.Create(m_painContainer, rcDefault, NULL,
            WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
            WS_VSCROLL | LBS_NOINTEGRALHEIGHT | LBS_NOTIFY |
            LBS_WANTKEYBOARDINPUT | LBS_SORT, WS_EX_CLIENTEDGE);

        m_painContainer.SetClient(m_viewFontList);
        m_wndSplitter.SetSplitterPane(SPLIT_PANE_LEFT, m_painContainer);

        // 右ペインのビューウィンドウを作成
        m_viewFontPreview.Create(m_wndSplitter, rcDefault, NULL,
            WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
            WS_EX_CLIENTEDGE);

        m_wndSplitter.SetSplitterPane(SPLIT_PANE_RIGHT, m_viewFontPreview);

        m_hWndClient = m_wndSplitter;
        UpdateLayout();

        // 分割バーの位置を設定
        m_wndSplitter.SetSplitterPos(120);

        // メッセージループにメッセージフィルタとアイドルハンドラを追加
        CMessageLoop* pLoop = _Module.GetMessageLoop();
        pLoop->AddMessageFilter(this);
        pLoop->AddIdleHandler(this);

        return 0;
    }

    void OnListSelChange(UINT uNotifyCode, int nID, HWND hWndCtl){
        // 現在選択されているアイテムを取得
        int nIndex = m_viewFontList.GetCurSel();
        if(nIndex != LB_ERR){
            CString strText;
            m_viewFontList.GetText(nIndex, strText);

            // 取得した文字列を右ペインに設定
            m_viewFontPreview.SetFontName(strText);
        }
    }

    void OnMenuChangeView(UINT uNotifyCode, int nID, HWND hWndCtl){
        if(m_wndSplitter.GetSinglePaneMode() == SPLIT_PANE_RIGHT){
            // 両ペイン表示
            m_wndSplitter.SetSinglePaneMode(SPLIT_PANE_NONE);
            UISetCheck(ID_MENUITEM_CHANGEVIEW, 1);
        }else{
            // 右ペインのみ表示
            m_wndSplitter.SetSinglePaneMode(SPLIT_PANE_RIGHT);
            UISetCheck(ID_MENUITEM_CHANGEVIEW, 0);
        }
    }

    void OnFileExit(UINT uNotifyCode, int nID, HWND hWndCtl){
        PostMessage(WM_CLOSE);
    }
};

 まず、CMainFrameクラス内でCPaneContainerのインスタンスをメンバ変数に追加します。CMainFrameクラスのWM_CREATEメッセージハンドラでは、まず、スプリッタウィンドウを親としてペインコンテナを作成します。この時、Create()の第1引数には親ウィンドウハンドル、第2引数にはペインコンテナに表示するタイトル文字列を指定します。なお、第2引数は文字列リソースIDでもかまいません。このほか、Create()にはウィンドウスタイル、拡張ウィンドウスタイル、ウィンドウ識別子、CREATESTRUCT構造体に含まれているウィンドウ作成データへのポインタを指定できます。

 なお、SetPaneContainerExtendedStyle()を呼び出すとペインコンテナ拡張スタイルを設定することができます。次のスタイルが指定できます。

ペインコンテナ拡張スタイル
拡張スタイル説明
PANECNT_NOCLOSEBUTTONペインコンテナの右上の[閉じる]ボタンを非表示
PANECNT_VERTICALペインコンテナのヘッダ(タイトルが表示される部分)を垂直に表示

 次に、ペインコンテナを親として左ペインのビューウィンドウを作成し、そのビューウィンドウのハンドルをSetClientを呼び出してペインコンテナにセットします。さらにそのペインコンテナをSetSplitterPane()によってスプリッタウィンドウの左ペインにセットします。

 このように、ビューウィンドウの親はペインコンテナであり、ペインコンテナの親はスプリッタウィンドウであり、スプリッタウィンドウの親はフレームウィンドウです。次に示すのはWTLのスプリッタウィンドウとペインコンテナを使ったアプリケーションのイメージ図です。

ウィンドウの関係
ウィンドウの関係

 最後に、ペインコンテナの右上にある[閉じる]ボタンを押したときの処理を追加します。このボタンを押すとIDがID_PANE_CLOSEのコマンドメッセージが発生するため、CMainFrameクラスのメッセージマップにエントリを追加してOnMenuChangeView()を呼び出しています。この関数は以前作成したもので、ビューの表示を切り換えます。

 ところで、ペインコンテナのメッセージマップにも、スプリッタウィンドウの場合と同様にFORWARD_NOTIFICATIONS()がエントリされています。このため、ビューウィンドウで発生したコマンドメッセージや通知メッセージは、その親であるペインコンテナへ送られ、さらにスプリッタウィンドウへ転送され、最後にフレームウィンドウへ届きます。

次のページ
ズームスクロールウィンドウ

この記事は参考になりましたか?

ATL/WTLを利用したVisual C++のWindowsプログラミング連載記事一覧

もっと読む

この記事の著者

So()

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/392 2006/05/26 00:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー