ホーム ATL/WTL
コマンドバー
ドキュメント種別 ATL/WTL に関する文書
最終更新日 2007/09/30
PR
 コマンドバーとは、InternetExplorerのメニューバーのようなグリップが付いていて移動可能なバーのことです。 WTLはコマンドバーを作成するためにCCommandBarCtrlクラスを用意しています。 CCommandBarCtrlクラスを使うと、 メニューリソースを用意するだけで簡単にコマンドバーを作成することができます。 また、ビットマップリソースを用意すると、メニューアイテムに画像を関連付けることができます。 (なお、画像はCCommandBarCtrlクラスのメンバ関数である SetImagesVisible(false)を呼び出すことによって非表示にすることもできます。)


さらに、コマンドバーの表示幅が足りない場合でも、 自動的にシェブロン(>>マーク)が有効になります。


もちろん、 普通のメニューバーのようにステータスバーにフライバイテキスト (メニューアイテム上にカーソルを置いた時にステータスバーに表示されるテキスト) を表示することができます。


 以下に示すのは、CCommandBarCtrlクラスを使用する例です。 フレームウィンドウを作成してコマンドバー、ツールバー、ステータスバーを追加します。 ツールバーは表示/非表示を切り換えられるようにします。

プロジェクトファイル ダウンロード
// stdafx.h
#pragma once

#include <atlbase.h>
#include <atlapp.h>
extern CAppModule _Module;
#include <atlwin.h>

#include <atlcrack.h>
#include <atlmisc.h>
#include <atlctrls.h>
#include <atlctrlw.h>  // CCommandBarCtrlを使用するため
#include <atlframe.h>
			

// MainFrm.h
#pragma once

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

    CCommandBarCtrl m_wndCmdBar;

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

    virtual BOOL OnIdle(){
        UIUpdateToolBar();
        UIUpdateStatusBar();
        return FALSE;
    }

    BEGIN_UPDATE_UI_MAP(CMainFrame)
        UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
    END_UPDATE_UI_MAP()

    BEGIN_MSG_MAP(CMainFrame)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)
        COMMAND_ID_HANDLER_EX(ID_VIEW_TOOLBAR, OnViewToolbar)
        COMMAND_ID_HANDLER_EX(ID_APP_EXIT, OnFileExit)
        CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
        CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
    END_MSG_MAP()

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

        // 既存のメニューバーをアタッチ
        m_wndCmdBar.AttachMenu(GetMenu());
        // メニューアイテムに関連付けられたツールバーの画像をロード
        m_wndCmdBar.LoadImages(IDR_MAINFRAME);
        // 既存のメニューバーを削除
        SetMenu(NULL);

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

        // リバーを作成し、コマンドバーとツールバーをバンドに追加
        CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
        AddSimpleReBarBand(hWndCmdBar);
        AddSimpleReBarBand(hWndToolBar, NULL, TRUE);

        // ステータスバーを作成
        CreateSimpleStatusBar();
        UIAddStatusBar(m_hWndStatusBar);

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

        return 0;
    }

    void OnDestroy(){
        // メッセージループからメッセージフィルタとアイドルハンドラを削除
        CMessageLoop* pLoop = _Module.GetMessageLoop();
        pLoop->RemoveMessageFilter(this);
        pLoop->RemoveIdleHandler(this);
        SetMsgHandled(false);
    }

    void OnViewToolbar(UINT uNotifyCode, int nID, CWindow wndCtl){
        static BOOL bVisible = TRUE;
        bVisible = !bVisible;
        CReBarCtrl rebar = m_hWndToolBar;
        int nBandIndex = rebar.IdToIndex(ATL_IDW_BAND_FIRST + 1);
        rebar.ShowBand(nBandIndex, bVisible);
        UISetCheck(ID_VIEW_TOOLBAR, bVisible);
        UpdateLayout();
    }

    void OnFileExit(UINT uNotifyCode, int nID, CWindow wndCtl){
        PostMessage(WM_CLOSE);
    }
};
			

// SampleProject.cpp
#include "stdafx.h"
#include "resource.h"
#include "MainFrm.h"

CAppModule _Module;

int WINAPI _tWinMain(HINSTANCE hInstance, 
    HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
    HRESULT hRes = ::CoInitialize(NULL);
    ATLASSERT(SUCCEEDED(hRes));

    ::DefWindowProc(NULL, 0, 0, 0L);

    AtlInitCommonControls(ICC_COOL_CLASSES | ICC_WIN95_CLASSES);

    hRes = _Module.Init(NULL, hInstance);
    ATLASSERT(SUCCEEDED(hRes));

    CMessageLoop theLoop;
    _Module.AddMessageLoop(&theLoop);

    CMainFrame wndMain;
    wndMain.CreateEx();
    wndMain.ShowWindow(nCmdShow);

    int nRet = theLoop.Run();

    _Module.RemoveMessageLoop();

    _Module.Term();
    ::CoUninitialize();

    return nRet;
}
			

 まず、プロジェクトにツールバーリソースを追加し、[ID]と[Prompt]を次のように設定します。 ボタンの種類は ATL/WTL AppWizard が生成するものと同じです。

リソース名 ID Prompt
ツールバー IDR_MAINFRAME -
ツールバーボタン ID_FILE_NEW 新しいドキュメントを作成します。\n新規作成
ツールバーボタン ID_FILE_OPEN 既存のドキュメントを開きます。\n開く
ツールバーボタン ID_FILE_SAVE 現在のドキュメントを保存します。\n上書き保存
ツールバーボタン ID_EDIT_CUT 選択範囲を切り取ってクリップボードに移動します。\n切り取り
ツールバーボタン ID_EDIT_COPY 選択範囲をクリップボードにコピーします。\nコピー
ツールバーボタン ID_EDIT_PASTE クリップボードの内容を挿入します。\n貼り付け
ツールバーボタン ID_FILE_PRINT 現在のドキュメントを印刷します。\n印刷
ツールバーボタン ID_APP_ABOUT プログラム情報、バージョン、著作権を表示します。\nバージョン情報



 次に、メニューバーの[ファイル]以下を次のように設定します。

リソース名 ID Caption Prompt
メニューアイテム ID_FILE_NEW 新規作成(&N) 新しいドキュメントを作成します。\n新規作成
メニューアイテム ID_FILE_OPEN 開く(&O)... 既存のドキュメントを開きます。\n開く
メニューアイテム ID_FILE_SAVE 上書き保存(&S) 現在のドキュメントを保存します。\n上書き保存
メニューアイテム ID_FILE_SAVE_AS 名前を付けて保存(&A)... 現在のドキュメントを新しい名前で保存します。\n名前を付けて保存
メニューアイテム ID_FILE_PRINT 印刷(&P)... 現在のドキュメントを印刷します。\n印刷
メニューアイテム ID_FILE_PRINT_PREVIEW 印刷プレビュー(&V) ページ全体を表示します。\n印刷プレビュー
メニューアイテム ID_FILE_PRINT_SETUP プリンタの設定(&R)... プリンタの設定を変更します。\nプリンタの設定
メニューアイテム ID_APP_EXIT アプリケーションの終了(&X) ドキュメントの保存を確認し、アプリケーションを終了します。\nアプリケーションの終了



 さらに、メニューバーに次のようなメニューアイテムを追加します。

リソース名 ID Caption Prompt
メニューアイテム(トップレベル) - 表示(&V) -
メニューアイテム ID_VIEW_TOOLBAR ツールバー(&T) ツールバーの表示/非表示を切り替えます。\nツールバー



 次に、stdafx.hヘッダでは、CCommandBarCtrlクラスを使用するためにatlctrlw.hヘッダをインクルードします。

 CMainFrameクラスではCCommandBarCtrlクラスのインスタンスをメンバ変数として宣言し、 WM_CREATEメッセージハンドラでCCommandBarCtrlクラスのメンバ関数であるCreate() を呼び出すことによってコマンドバーを作成します。 Create()の引数には順に親ウィンドウのハンドル、ウィンドウ位置、ウィンドウ名、 ウィンドウスタイル、拡張ウィンドウスタイル、ウィンドウID、ウィンドウ作成データを指定でき、 ここではウィンドウスタイルにATL_SIMPLE_CMDBAR_PANE_STYLEを指定します。 このスタイルはatlctrlw.hヘッダで次のように定義されています。 なお、表示上の都合で改行位置などを変更しています。

// atlctrlw.h
// Window Styles:
#define CBRWS_TOP            CCS_TOP
#define CBRWS_BOTTOM         CCS_BOTTOM
#define CBRWS_NORESIZE       CCS_NORESIZE
#define CBRWS_NOPARENTALIGN  CCS_NOPARENTALIGN
#define CBRWS_NODIVIDER      CCS_NODIVIDER

// standard command bar styles
#define ATL_SIMPLE_CMDBAR_PANE_STYLE \
    (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | \
    CBRWS_NODIVIDER | CBRWS_NORESIZE | CBRWS_NOPARENTALIGN)
			

次に、コマンドバーにメニューアイテムを追加します。 今回の例ではAttachMenu()を呼び出すことによって、 フレームウィンドウのメニューバーからメニューアイテムを読み込んでいますが、 LoadMenu()を呼び出してメニューリソースから直接アイテムをロードすることもできます。

// コマンドバーを作成
HWND hWndCmdBar = m_wndCmdBar.Create(m_hWnd,
    rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);

// メニューリソースをロード
m_wndCmdBar.LoadMenu(IDR_MAINFRAME);
			

次に、LoadImages()を呼び出してツールバーの画像をロードします。 これにより、IDが等しいメニューアイテムとツールバーの画像が関連付けられ、 メニューアイテムの横に画像が表示されるようになります。 なお、メニューアイテムの横に画像を表示するためには、 AddBitmap()AddIcon()を使うこともできます。

次に、ツールバーとリバーを作成し、バンドにコマンドバーとツールバーを追加します。 ツールバーはコマンドバーの下に追加するため、 AddSimpleReBarBandの第3引数にはTRUEを指定します。

 次に、リソースIDがID_VIEW_TOOLBARWM_COMMANDメッセージハンドラとしてOnViewToolbar()を追加します。 このハンドラ関数では静的変数bVisibleによってツールバーの可視状態を保持し、 CReBarCtrlクラスのメンバ関数であるShowBand()で可視状態を切り換えています。 なお、このハンドラ関数のコードは ATL/WTL AppWizard が出力するものとほぼ同じです。

 最後に、tWinMain()で、引数にICC_COOL_CLASSESICC_WIN95_CLASSESを指定してAtlInitCommonControls()を呼び出します。

コマンドバースタイルのポップアップメニュー
 コマンドバースタイルのポップアップメニューを作成するためには、 CCommandBarCtrlのメンバ関数であるTrackPopupMenu()を呼び出します。


以下に示すのは、コマンドバースタイルのポップアップメニューを表示するコードの例です。 先述のプログラムに以下のコードを追加することにより、 クライアント領域を右クリックしたときにインデックス 0 のコマンドバーメニューアイテム([ファイル]以下)がポップアップメニューとして表示されます。

プロジェクトファイル ダウンロード
// MainFrm.h
BEGIN_MSG_MAP(CMainFrame)
    MSG_WM_CONTEXTMENU(OnContextMenu)
    ...
    ...
END_MSG_MAP()

void OnContextMenu(CWindow wnd, CPoint point){
    // [Shift]+[F10]キーが押された場合は座標をクライアント領域の左上に設定
    if(point.x == -1 && point.y == -1){
        point.SetPoint(0, 0);
        ClientToScreen(&point);
    }

    // 座標がクライアント領域内の場合のみポップアップメニューを表示
    CRect rc;
    GetClientRect(&rc);
    ClientToScreen(&rc);
    if(rc.PtInRect(point)){
        // コマンドバーのメニューハンドルを取得
        CMenuHandle menu = m_wndCmdBar.GetMenu();

        // インデックス0のメニューアイテムをポップアップメニューとして表示
        m_wndCmdBar.TrackPopupMenu(menu.GetSubMenu(0), 
            TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, point.x, point.y, NULL);
    }else{
        SetMsgHandled(false);
    }
}
			

このように、ポップアップメニューをコマンドバースタイルで表示するためには TrackPopupMenu()の第1引数に表示するメニューのハンドルを指定します。