ホーム WTL Mobile
ステータスバー
ドキュメント種別 ATL/WTL に関する文書
最終更新日 2010/01/02
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

#define WINVER 0x0420
#include <atlbase.h>
#if _ATL_VER == 0x900
#define _SECURE_ATL 1
#endif

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

#include <tpcshell.h>
#include <aygshell.h>
#pragma comment(lib, "aygshell.lib")

#include <atlcrack.h>
#include <atlmisc.h>
#include <atlframe.h>
#include <atlctrls.h>
#define _WTL_CE_NO_ZOOMSCROLL
#define _WTL_CE_NO_FULLSCREEN
#include <atlwince.h>
			

// SampleProjectFrame.h
#pragma once

class CSampleProjectFrame : 
    public CFrameWindowImpl<CSampleProjectFrame>,
    public CUpdateUI<CSampleProjectFrame>,
    public CAppWindow<CSampleProjectFrame>,
    public CMessageFilter, public CIdleHandler
{
public:
    DECLARE_APP_FRAME_CLASS(NULL, IDR_MAINFRAME, L"Software\\WTL")

    CStatusBarCtrl m_statusbar;

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

    virtual BOOL OnIdle(){
        return FALSE;
    }

    BEGIN_UPDATE_UI_MAP(CSampleProjectFrame)
    END_UPDATE_UI_MAP()

    BEGIN_MSG_MAP(CSampleProjectFrame)
        MSG_WM_LBUTTONDOWN(OnLButtonDown)
        MSG_WM_SIZE(OnSize)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)
        COMMAND_ID_HANDLER_EX(ID_APP_EXIT, OnAppExit)
        CHAIN_MSG_MAP(CAppWindow<CSampleProjectFrame>)
        CHAIN_MSG_MAP(CUpdateUI<CSampleProjectFrame>)
        CHAIN_MSG_MAP(CFrameWindowImpl<CSampleProjectFrame>)
    END_MSG_MAP()

    void OnLButtonDown(UINT nFlags, CPoint point){
        SHRGINFO info;
        info.cbSize = sizeof(SHRGINFO);
        info.hwndClient = m_hWnd;
        info.ptDown.x = point.x;
        info.ptDown.y = point.y;
        info.dwFlags = SHRG_RETURNCMD;

        if(SHRecognizeGesture(&info) == GN_CONTEXTMENU){
            CString strPos;
            strPos.Format(_T("X: %d, Y: %d"), point.x, point.y);
            m_statusbar.SetText(1, strPos);
        }
    }

    void OnSize(UINT nType, CSize size){
        if(m_statusbar.m_hWnd != NULL){
            // マウス座標を表示するペインの幅
            int cxPosPane = 90;

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

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

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

    int OnCreate(LPCREATESTRUCT lpCreateStruct){
        // メニューバー作成
        CreateSimpleCEMenuBar(IDR_MAINFRAME, SHCMBF_HMENU);

        // ステータスバー作成
        CreateSimpleStatusBar(_T("レディ"));
        m_statusbar = 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 OnAppExit(UINT uNotifyCode, int nID, CWindow wndCtl){
        PostMessage(WM_CLOSE);
    }
};
			

// SampleProject.cpp
#include "stdafx.h"
#include "resourceppc.h"
#include "SampleProjectFrame.h"

CAppModule _Module;

int WINAPI _tWinMain(HINSTANCE hInstance,
    HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
    HRESULT hRes =
        CSampleProjectFrame::ActivatePreviousInstance(hInstance, lpstrCmdLine);

    if(FAILED(hRes) || S_FALSE == hRes){
        return hRes;
    }

    hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
    ATLASSERT(SUCCEEDED(hRes));

    AtlInitCommonControls(ICC_BAR_CLASSES);
    SHInitExtraControls();

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

    int nRet = CSampleProjectFrame::AppRun(lpstrCmdLine, nCmdShow);

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

    return nRet;
}
			

 まず、プロジェクトにメニューリソースを追加し、[ID]と[Caption]を次のように設定します。

リソース名 ID Caption
メニュー IDR_MAINFRAME -
メニューアイテム(トップレベル) ID_APP_EXIT 終了



 CSampleProjectFrameクラスでは、まず、 ステータスバーコントロール用にCStatusBarCtrlクラスのインスタンスをメンバ変数として宣言します。 これを使うためには、WM_CREATEメッセージハンドラでCreateSimpleStatusBar()を呼び出した後に、 ステータスバーのハンドルであるm_hWndStatusBarを代入する必要があります。

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

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

 最後に_tWinMain()で、引数にICC_BAR_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

#define WINVER 0x0420
#include <atlbase.h>
#if _ATL_VER == 0x900
#define _SECURE_ATL 1
#endif

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

#include <tpcshell.h>
#include <aygshell.h>
#pragma comment(lib, "aygshell.lib")

#include <atlcrack.h>
#include <atlmisc.h>
#include <atlframe.h>
#include <atlctrls.h>
#define _WTL_CE_NO_ZOOMSCROLL
#define _WTL_CE_NO_FULLSCREEN
#include <atlwince.h>
#include <atlctrlx.h>  // CMultiPaneStatusBarCtrlを使用するため
			

// SampleProjectFrame.h
#pragma once

class CSampleProjectFrame : 
    public CFrameWindowImpl<CSampleProjectFrame>,
    public CUpdateUI<CSampleProjectFrame>,
    public CAppWindow<CSampleProjectFrame>,
    public CMessageFilter, public CIdleHandler
{
public:
    DECLARE_APP_FRAME_CLASS(NULL, IDR_MAINFRAME, L"Software\\WTL")

    CMultiPaneStatusBarCtrl m_statusbar;

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

    virtual BOOL OnIdle(){
        return FALSE;
    }

    BEGIN_UPDATE_UI_MAP(CSampleProjectFrame)
    END_UPDATE_UI_MAP()

    BEGIN_MSG_MAP(CSampleProjectFrame)
        MSG_WM_LBUTTONDOWN(OnLButtonDown)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)
        COMMAND_ID_HANDLER_EX(ID_APP_EXIT, OnAppExit)
        CHAIN_MSG_MAP(CAppWindow<CSampleProjectFrame>)
        CHAIN_MSG_MAP(CUpdateUI<CSampleProjectFrame>)
        CHAIN_MSG_MAP(CFrameWindowImpl<CSampleProjectFrame>)
    END_MSG_MAP()

    void OnLButtonDown(UINT nFlags, CPoint point){
        SHRGINFO info;
        info.cbSize = sizeof(SHRGINFO);
        info.hwndClient = m_hWnd;
        info.ptDown.x = point.x;
        info.ptDown.y = point.y;
        info.dwFlags = SHRG_RETURNCMD;

        if(SHRecognizeGesture(&info) == GN_CONTEXTMENU){
            CString strPos;
            strPos.Format(_T("X: %d, Y: %d"), point.x, point.y);
            m_statusbar.SetPaneText(IDS_PANE_POS, strPos);
        }
    }

    int OnCreate(LPCREATESTRUCT lpCreateStruct){
        // メニューバー作成
        CreateSimpleCEMenuBar(IDR_MAINFRAME, SHCMBF_HMENU);

        // ステータスバー作成
        m_hWndStatusBar = m_statusbar.Create(m_hWnd, _T("レディ"), 
            WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);

        // ステータスバーにペインを設定
        int nPanes[] = {ID_DEFAULT_PANE, IDS_PANE_POS};
        m_statusbar.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 OnAppExit(UINT uNotifyCode, int nID, CWindow wndCtl){
        PostMessage(WM_CLOSE);
    }
};
			

// SampleProject.cpp
#include "stdafx.h"
#include "resourceppc.h"
#include "SampleProjectFrame.h"

CAppModule _Module;

int WINAPI _tWinMain(HINSTANCE hInstance,
    HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
    HRESULT hRes =
        CSampleProjectFrame::ActivatePreviousInstance(hInstance, lpstrCmdLine);

    if(FAILED(hRes) || S_FALSE == hRes){
        return hRes;
    }

    hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
    ATLASSERT(SUCCEEDED(hRes));

    AtlInitCommonControls(ICC_BAR_CLASSES);
    SHInitExtraControls();

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

    int nRet = CSampleProjectFrame::AppRun(lpstrCmdLine, nCmdShow);

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

    return nRet;
}
			

 まず、プロジェクトに文字列リソースを追加し、[ID]と[Caption]を次のように設定します。

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



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

 CSampleProjectFrameクラスでは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_LBUTTONDOWNメッセージハンドラでSetPaneTextを呼び出し、 IDがIDS_PANE_POSのペインにクライアント座標を表示します。

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