ホーム ATL/WTL
ステータスバー
ドキュメント種別 ATL/WTL に関する文書
最終更新日 2007/09/30
PR
 WTLではコモンコントロールのステータスバーコントロールをCStatusBarCtrlT というクラステンプレートでカプセル化しています。 テンプレート引数にはクラスを指定しますが、 そのクラスはCStatusBarCtrlTの基底クラスとして使用されます。 atlctrls.hヘッダではtypedefによって次のように宣言されています。

// atlctrls.h
typedef CStatusBarCtrlT<ATL::CWindow>   CStatusBarCtrl;
			

これは、CStatusBarCtrlクラスはCWindowクラスの派生クラスであることを意味します。

 WTLのCStatusBarCtrlクラスは、MFCの同名のクラスとほぼ同じメンバ関数を用意しています。 以下に示すのは、CStatusBarCtrlクラスを使用する例です。 フレームウィンドウを作成してステータスバーを追加し、 そのステータスバーの2番目のペインにフレームウィンドウのクライアント領域上のマウス座標を表示します。


プロジェクトファイル ダウンロード
// 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 <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)

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

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

    BEGIN_UPDATE_UI_MAP(CMainFrame)
        // エントリなし
    END_UPDATE_UI_MAP()

    BEGIN_MSG_MAP(CMainFrame)
        MSG_WM_MOUSEMOVE(OnMouseMove)
        MSG_WM_SIZE(OnSize)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)
        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){
        // ステータスバーを作成
        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 OnSize(UINT nType, CSize size){
        // マウス座標を表示するペインの幅
        int cxPosPane = 90;

        // デフォルトペインの幅
        CRect rcClient;
        GetClientRect(rcClient);
        int cxDefaultPane = rcClient.right - cxPosPane
            - ::GetSystemMetrics(SM_CXVSCROLL) - ::GetSystemMetrics(SM_CXEDGE);

        // ステータスバーにペインを設定
        CStatusBarCtrl bar = m_hWndStatusBar;
        int nPanes[] = {cxDefaultPane, cxDefaultPane + cxPosPane};
        bar.SetParts(sizeof(nPanes)/sizeof(nPanes[0]), nPanes);

        // 基底クラスのWM_SIZEメッセージハンドラも呼び出すため
        SetMsgHandled(false);
    }

    void OnMouseMove(UINT nFlags, CPoint point){
        CString strPos;
        strPos.Format(_T("X:%d, Y:%d"), point.x, point.y);

        CStatusBarCtrl bar = m_hWndStatusBar;
        bar.SetText(1, strPos);
    }

    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_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;
}
			

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

 CMainFrameクラスでは一般的なフレームウィンドウを作成します。 WM_CREATEメッセージハンドラではCreateSimpleStatusBar()を呼び出してステータスバーを作成します。 これにより、フレームウィンドウのメンバ変数であるm_hWndStatusBarにステータスバーのハンドルが設定されます。

 次に、WM_SIZEメッセージハンドラを追加します。 ここではステータスバーに2つのペインを追加します。 1番目はフレームウィンドウの大きさに合わせて幅を調整するデフォルトペインで、 2番目はフレームウィンドウのクライアント領域上のマウス座標を表示するペインです。 ペインを設定するにはCStatusBarCtrlクラスのメンバ関数であるSetParts()を呼び出します。 SetParts()の第1引数にはペインの数、第2引数にはペインの右端の座標を要素とする配列を指定します。 なお、WM_SIZEメッセージは基底クラスである CFrameWindowImplのメッセージマップでもマッピングされているため、 最後にSetMsgHandled(false)を呼び出す必要があります。

 次に、WM_MOUSEMOVEメッセージハンドラを追加します。 ここではCStatusBarCtrlクラスのメンバ関数であるSetText()を呼び出して、 クライアント座標をステータスバーの2番目のペイン(インデックスは1)に表示します。

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

マルチペインステータスバー
 先述の例ではステータスバーに複数のペイン(マルチペイン)を設定するために、 WM_SIZEメッセージハンドラを追加してSetParts()を呼び出しました。 WTLはこのような作業を簡略化するために、CMultiPaneStatusBarCtrlというクラスを用意しています。 CMultiPaneStatusBarCtrlクラスはCStatusBarCtrlクラスの派生クラスで、 atlctrlx.hヘッダでは次のように定義されています。

// atlctrlx.h
template <class T, class TBase = CStatusBarCtrl>
class ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl : public ATL::CWindowImpl< T, TBase >
{
    ...
    ...
};

class CMultiPaneStatusBarCtrl
    : public CMultiPaneStatusBarCtrlImpl<CMultiPaneStatusBarCtrl>
{
public:
    DECLARE_WND_SUPERCLASS(_T("WTL_MultiPaneStatusBar"), GetWndClassName())
};
			

 次に示すのは、先述のプログラムをCMultiPaneStatusBarCtrlクラスを使用して書き換える例です。

プロジェクトファイル ダウンロード
// 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 <atlctrlx.h>  // CMultiPaneStatusBarCtrlを使用するため
#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)

    CMultiPaneStatusBarCtrl m_wndStatusBar;

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

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

    BEGIN_UPDATE_UI_MAP(CMainFrame)
        // エントリなし
    END_UPDATE_UI_MAP()

    BEGIN_MSG_MAP(CMainFrame)
        MSG_WM_MOUSEMOVE(OnMouseMove)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)
        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){
        // ステータスバーを作成
        m_hWndStatusBar = m_wndStatusBar.Create(m_hWnd);
        UIAddStatusBar(m_hWndStatusBar);

        // ステータスバーにペインを設定
        int nPanes[] = {ID_DEFAULT_PANE, IDS_PANE_POS};
        m_wndStatusBar.SetPanes(nPanes, sizeof(nPanes)/sizeof(nPanes[0]));

        // メッセージループにメッセージフィルタとアイドルハンドラを追加
        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 OnMouseMove(UINT nFlags, CPoint point){
        CString strPos;
        strPos.Format(_T("X:%d, Y:%d"), point.x, point.y);
        m_wndStatusBar.SetPaneText(IDS_PANE_POS, strPos);
    }

    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_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]と[Caption]を次のように設定します。

リソース名 ID Caption
文字列 IDS_PANE_POS X: 0000, Y: 0000



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

 CMainFrameクラスではCMultiPaneStatusBarCtrl クラスのインスタンスをメンバ変数として宣言し、 WM_CREATEメッセージハンドラでCMultiPaneStatusBarCtrlのメンバ関数であるCreate() を呼び出すことによってマルチペインステータスバーを作成します。 Create()は戻り値としてステータスバーのハンドルを返すので、 それをフレームウィンドウのメンバ変数であるm_hWndStatusBarに代入します。

なお、Create()には2つのバージョンがあります。 一方は第2引数に文字列を指定するもので、他方は第2引数に文字列リソースのIDを指定するものです。 第2引数を省略した場合は後者のCreate()が呼び出され、 デフォルトの文字列リソースIDとしてATL_IDS_IDLEMESSAGEが指定されます。 両バージョンとも第1引数に親ウィンドウハンドルを指定し、 第3引数にはスタイル、第4引数にはIDを指定できます。 第3引数を省略した場合はデフォルトスタイルとして WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP が指定され、第4引数を省略した場合はデフォルトIDとしてATL_IDW_STATUS_BARが指定されます。

 次に、SetPanes()を呼び出してステータスバーにペインを設定します。 第1引数には文字列リソースのIDを要素とした配列を指定し、第2引数にはペインの数を指定します。 SetPanes()は配列内の文字列リソースIDから文字列を取得し、 その文字列の幅と同じ大きさのペインを作成します。 なお、今回の例で配列の1番目の要素に指定したID_DEFAULT_PANEは、WTLが用意しているIDで、 フレームウィンドウのサイズが変更されるたびに自動的に幅が調整されるペインを意味します。

 次に、WM_MOUSEMOVEメッセージハンドラでSetPaneTextを呼び出し、 IDがIDS_PANE_POSのペインにクライアント座標を表示します。

 最後に、WM_SIZEメッセージハンドラを削除します。 CMultiPaneStatusBarCtrlクラスは内部にWM_SIZEメッセージハンドラを用意しており、 フレームウィンドウのサイズが変更されるたびに、ステータスバーのペインの位置とサイズを自動的に調整します。