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

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

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

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


// stdafx.h内
#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内
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_EX(CMainFrame)
        MSG_WM_MOUSEMOVE(OnMouseMove)
        MSG_WM_SIZE(OnSize)
        MSG_WM_CREATE(OnCreate)
        COMMAND_ID_HANDLER_EX(ID_APP_EXIT, OnMenuExit)
        CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
        CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
    END_MSG_MAP()

    LRESULT OnCreate(LPCREATESTRUCT lpcs){
        // ステータスバーを作成
        CreateSimpleStatusBar();
        UIAddStatusBar(m_hWndStatusBar);

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

        return 0;
    }

    void OnSize(UINT uType, 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 uFlags, CPoint ptClient){
        CString strPos;
        strPos.Format(_T("X:%d, Y:%d"), ptClient.x, ptClient.y);

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

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

// app.cpp内
#include "stdafx.h"

#include "resource.h"

#include "mainfrm.h"

CAppModule _Module;

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR lpCmdLine, 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));

    int nRet = 0;
    // BLOCK: アプリケーション実行
    {
        CMessageLoop theLoop;
        _Module.AddMessageLoop(&theLoop);

        CMainFrame wnd;
        wnd.CreateEx();
        wnd.ShowWindow(nCmdShow);
        wnd.UpdateWindow();

        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番目はフレームウィンドウのクライアント領域上のマウス座標を表示するペインです。 ペインを設定するにはSetParts()を呼び出します。 第1引数にはペインの数、第2引数にはペインの右端の座標を要素とする配列へのポインタを指定します。 なお、WM_SIZEメッセージは基底クラスである CFrameWindowImplクラス内でもマッピングされているため、 最後にSetMsgHandled(false)を呼び出す必要があります。

 次に、WM_MOUSEMOVEメッセージハンドラを追加します。 ここではクライアント座標を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内
#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内
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_EX(CMainFrame)
        MSG_WM_MOUSEMOVE(OnMouseMove)
        MSG_WM_CREATE(OnCreate)
        COMMAND_ID_HANDLER_EX(ID_APP_EXIT, OnMenuExit)
        CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
        CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
    END_MSG_MAP()

    LRESULT OnCreate(LPCREATESTRUCT lpcs){
        // ステータスバーを作成
        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 OnMouseMove(UINT uFlags, CPoint ptClient){
        CString strPos;
        strPos.Format(_T("X:%d, Y:%d"), ptClient.x, ptClient.y);
        m_wndStatusBar.SetPaneText(IDS_PANE_POS, strPos);
    }

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

// Control.cpp内
#include "stdafx.h"

#include "resource.h"

#include "mainfrm.h"

CAppModule _Module;

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR lpCmdLine, 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));

    int nRet = 0;
    // BLOCK: アプリケーション実行
    {
        CMessageLoop theLoop;
        _Module.AddMessageLoop(&theLoop);

        CMainFrame wnd;
        wnd.CreateEx();
        wnd.ShowWindow(nCmdShow);
        wnd.UpdateWindow();

        nRet = theLoop.Run();

        _Module.RemoveMessageLoop();
    }

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

    return nRet;
}
			

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

 CMainFrameクラスではCMultiPaneStatusBarCtrl クラスのインスタンスをメンバ変数として宣言し、 WM_CREATEメッセージハンドラで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から文字列を取得し、 その文字列の幅と同じ大きさのペインを作成します。 ここではマウス座標を表示するために、 IDがIDS_PANE_POSという文字列リソースを用意し、 キャプションとして「X: 0000, Y: 0000」を設定します。 これは、幅と高さがそれぞれ4桁まで表示できるサイズのペインを作成することを意味します。



なお、配列の1番目に指定したID_DEFAULT_PANEはWTLが用意しているIDで、 フレームウィンドウのサイズが変更されるたびに、それに合わせて大きさが調整されるペインを意味します。

 次に、WM_MOUSEMOVEメッセージハンドラでは、 SetPaneTextによってステータスバーのIDがIDS_PANE_POSのペインにクライアント座標を表示しています。

 この例ではWM_SIZEメッセージハンドラを作成していません。 これは、CMultiPaneStatusBarCtrlクラス内には WM_SIZEメッセージハンドラがあり、 フレームウィンドウのサイズを変更するたびに、 ステータスバーのペインが自動的に調節されるためです。