WTLはスクロールウィンドウを作成するためにCScrollWindowImplというクラステンプレートを用意しています。
これはATLのCWindowImplクラステンプレートのように基底クラスとしてのみ使用し、
テンプレート引数の種類もCWindowImplと同じです。
以下に示すのは、CScrollWindowImplをベースとしたビューウィンドウを作成する例です。
プロジェクトにView.hというヘッダファイルを追加し、そこにCScrollViewというクラスを定義します。
メニューバーには、ウィンドウを上下左右にスクロールするためのメニューアイテムを追加します。
// View.h
#pragma once
class CScrollView : public CScrollWindowImpl<CScrollView>
{
public:
BOOL PreTranslateMessage(MSG* pMsg){
return FALSE;
}
BEGIN_MSG_MAP(CScrollView)
MSG_WM_CREATE(OnCreate)
CHAIN_MSG_MAP(CScrollWindowImpl<CScrollView>)
CHAIN_MSG_MAP_ALT(CScrollWindowImpl<CScrollView>, 1)
END_MSG_MAP()
int OnCreate(LPCREATESTRUCT lpCreateStruct){
LRESULT lRet = DefWindowProc();
SetScrollSize(640, 480);
SetScrollLine(10, 10);
SetScrollPage(100, 100);
return lRet;
}
void DoPaint(CDCHandle dc){
// スクロールウィンドウの中央に文字列を描画
CSize size;
GetScrollSize(size);
CRect rect(0, 0, size.cx, size.cy);
dc.DrawText(_T("Hello, ATL/WTL"),
-1, rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
};
|
CScrollViewクラスはCScrollWindowImplから派生し、
メッセージマップにはWM_CREATEメッセージエントリとCScrollWindowImplへのチェインを追加します。
WM_CREATEメッセージハンドラではスクロールウィンドウのサイズやスクロールバーの移動量を設定します。
次に、基底クラスであるCScrollWindowImplのメンバ関数DoPaint()をオーバーライドします。
この関数はCScrollWindowImplで用意されているWM_PAINTメッセージハンドラから呼び出され、
ここにビューへの描画コードを記述することで、スクロールバーに合わせて描画内容も自動的にスクロールされるようになります。
今回の例ではスクロールウィンドウの中央に文字列を描画します。
CScrollWindowImplは代替メッセージマップも用意しています。
これは、ビューを上下左右にスクロールするためのWM_COMMANDメッセージをマッピングしています。
WTLはスクロールウィンドウを操作するためにデフォルトで次のようなIDを用意しています。
| ID |
操作 |
| ID_SCROLL_UP |
上にスクロール |
| ID_SCROLL_DOWN |
下にスクロール |
| ID_SCROLL_PAGE_UP |
前のページ |
| ID_SCROLL_PAGE_DOWN |
次のページ |
| ID_SCROLL_TOP |
最上部 |
| ID_SCROLL_BOTTOM |
最下部 |
| ID_SCROLL_LEFT |
左にスクロール |
| ID_SCROLL_RIGHT |
右にスクロール |
| ID_SCROLL_PAGE_LEFT |
左のページ |
| ID_SCROLL_PAGE_RIGHT |
右のページ |
| ID_SCROLL_ALL_LEFT |
左の端 |
| ID_SCROLL_ALL_RIGHT |
右の端 |
このように、CScrollWindowImplにはメッセージマップが用意されており、
WM_CREATEメッセージやWM_PAINTメッセージ、その他
WM_VSCROLL、WM_HSCROLL、WM_MOUSEWHEEL、
WM_SIZE、WM_SETTINGCHANGE、WM_PRINTCLIENTメッセージをマッピングしているため、
少ない作業で基本的な機能を持ったスクロールウィンドウを作成することができます。
次に示すのは、CScrollViewクラスを使用する例です。
// 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 <atlscrl.h> // CScrollWindowImplを使用するため
|
// 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")
CScrollView m_view;
virtual BOOL PreTranslateMessage(MSG* pMsg){
if(CFrameWindowImpl<CSampleProjectFrame>::PreTranslateMessage(pMsg))
return TRUE;
return m_view.IsWindow() ? m_view.PreTranslateMessage(pMsg) : FALSE;
}
virtual BOOL OnIdle(){
return FALSE;
}
BEGIN_UPDATE_UI_MAP(CSampleProjectFrame)
END_UPDATE_UI_MAP()
BEGIN_MSG_MAP(CSampleProjectFrame)
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>)
CHAIN_CLIENT_COMMANDS() // ビュークラスへコマンドチェイン
END_MSG_MAP()
int OnCreate(LPCREATESTRUCT lpCreateStruct){
// メニューバー作成
CreateSimpleCEMenuBar(IDR_MAINFRAME, SHCMBF_HMENU);
// ビューを作成
m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
// メッセージループにメッセージフィルタとアイドルハンドラを追加
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 "View.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_DATE_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 |
終了 |
| メニューアイテム(トップレベル) |
- |
表示 |
| メニューアイテム |
ID_SCROLL_UP |
上にスクロール |
| メニューアイテム |
ID_SCROLL_DOWN |
下にスクロール |
| メニューアイテム |
ID_SCROLL_LEFT |
左にスクロール |
| メニューアイテム |
ID_SCROLL_RIGHT |
右にスクロール |

次に、stdafx.hヘッダでは、CScrollWindowImplを使用するためにatlscrl.hヘッダをインクルードします。
次に、CScrollViewクラスのインスタンスを
CSampleProjectFrameクラスのメンバ変数として宣言し、
WM_CREATEメッセージハンドラでCreate()を呼び出してビューウィンドウを作成します。
Create()の引数の種類はCWindowImpl::Create()と同じです。
CSampleProjectFrameクラスのメッセージマップにはコマンドチェインを追加します。
これにより、メニューアイテムのWM_COMMANDメッセージがフレームウィンドウからビューウィンドウへ転送され、
さらにCScrollViewクラスの代替メッセージマップへのチェインによってCScrollWindowImplの代替メッセージマップに転送されます。
CScrollWindowImplでは間接的にDoScroll()というメンバ関数が呼び出され、
そこで上下左右のスクロール処理が行われます。
最後に、SampleProject.cppファイルでSampleProjectFrame.hヘッダの前にView.hヘッダをインクルードします。
|