はじめに
前回は、スプリッタウィンドウを利用したプログラムを作成しました。今回は、前回のプログラムを拡張してマルチペインステータスバーやペインコンテナ、ズームスクロールウィンドウの使い方について説明します。
対象読者
ATL/WTLによるWindowsプログラミングに興味があり、C++やWin32APIによるWindowsプログラミングの基本的な知識がある方。
必要な環境
サンプルはVisual C++ 6.0で作成し、Windows 2000で動作確認しています。
マルチペインステータスバー
「マルチペインステータスバー」とは、複数のペインを持つステータスバーのことです。WTLは、簡単にステータスバーに複数ペインを設定できる機能を備えたCMultiPaneStatusBarCtrl
を用意しています。
前回作成したプログラムのステータスバーを、CMultiPaneStatusBarCtrl
に置き換えた例を示します。
#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 <atlctrlw.h> #include <atlframe.h> #include <atlsplit.h>
class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>, public CMessageFilter, public CIdleHandler { public: DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME) CSplitterWindow m_wndSplitter; // スプリッタウィンドウ 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_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_viewFontList.Create(m_wndSplitter, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL | LBS_NOINTEGRALHEIGHT | LBS_NOTIFY | LBS_WANTKEYBOARDINPUT | LBS_SORT, WS_EX_CLIENTEDGE); m_wndSplitter.SetSplitterPane(SPLIT_PANE_LEFT, m_viewFontList); // 右ペインのビューウィンドウを作成 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); } };
まず、プロジェクトに文字列リソース(リソースID:IDS_PANE_COUNT
)を追加し、「フォント数:0000」という文字列を割り当てます。
次に、CMultiPaneStatusBarCtrl
を使用するために「stdafx.h」で「atlctrlx.h」をインクルードします。
残りの変更点はCMainFrame
クラス内です。まず、CMainFrame
のメンバ変数としてCMultiPaneStatusBarCtrl
のインスタンスm_wndStatusBar
を宣言します。
CMainFrame
クラスのWM_CREATE
メッセージハンドラでは、m_wndStatusBar
に対して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から文字列を取得し、その文字列の幅と同じ大きさのペインを作成します。本稿では、ステータスバーの2番目のペインにフォント数を表示するためにIDS_PANE_COUNT
という文字列リソースを追加したので、「フォント数:0000」という文字列が表示できるサイズのペインを作成することを意味します。このペインに文字列を設定するのはOnIdle()
のSetPaneText()
です。
なお、配列の1番目に指定したID_DEFAULT_PANE
はWTLが用意しているIDで、フレームウィンドウのサイズが変更されるたびに、それに合わせて大きさが調整されるペインを意味します。
本稿ではWM_SIZE
メッセージハンドラを削除しました。これは、CMultiPaneStatusBarCtrl
内にはWM_SIZE
メッセージハンドラがあり、フレームウィンドウのサイズを変更するたびに、ステータスバーのペインが自動的に調節されるためです。