ホーム ATL/WTL
スクロール
ドキュメント種別 ATL/WTL に関する文書
最終更新日 2007/10/06
PR
 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);

        SetMsgHandled(false);

        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メッセージエントリと基底クラスへのチェインを追加します。 WM_CREATEメッセージハンドラではスクロールウィンドウのサイズやスクロールバーの移動量を設定し、 SetMsgHandled(false)を呼び出します。 これは基底クラスでも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_VSCROLLWM_HSCROLLWM_MOUSEWHEELWM_SIZEWM_SETTINGCHANGEWM_PRINTCLIENTメッセージをマッピングしているため、 少ない作業で基本的な機能を持ったスクロールウィンドウを作成することができます。

 次に示すのは、CScrollViewクラスを使用する例です。

プロジェクトファイル ダウンロード
// stdafx.h
#pragma once

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

#include <atlcrack.h>
#include <atlmisc.h>
#include <atlframe.h>
#include <atlscrl.h>    // CScrollWindowImplを使用するため
			

// MainFrm.h
#pragma once

class CMainFrame : public CFrameWindowImpl<CMainFrame>,
    public CUpdateUI<CMainFrame>, public CMessageFilter, public CIdleHandler
{
public:
    DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)

    CScrollView m_view;

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

        return m_view.PreTranslateMessage(pMsg);
    }

    virtual BOOL OnIdle(){
        return FALSE;
    }

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

    BEGIN_MSG_MAP(CMainFrame)
        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>)
        CHAIN_CLIENT_COMMANDS()    // ビュークラスへコマンドチェイン
    END_MSG_MAP()

    int OnCreate(LPCREATESTRUCT lpCreateStruct){
        // ビューを作成
        m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL,
            WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
            WS_EX_CLIENTEDGE);

        // メッセージループにメッセージフィルタとアイドルハンドラを追加
        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 OnFileExit(UINT uNotifyCode, int nID, CWindow wndCtl){
        PostMessage(WM_CLOSE);
    }
};
			

// SampleProject.cpp
#include "stdafx.h"
#include "resource.h"
#include "View.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_BAR_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 Prompt
メニューアイテム(トップレベル) - 表示(&V) -
メニューアイテム ID_SCROLL_UP 上にスクロール(&U) ウィンドウを上にスクロールします。\n上にスクロール
メニューアイテム ID_SCROLL_DOWN 下にスクロール(&D) ウィンドウを下にスクロールします。\n下にスクロール
メニューアイテム ID_SCROLL_LEFT 左にスクロール(&L) ウィンドウを左にスクロールします。\n左にスクロール
メニューアイテム ID_SCROLL_RIGHT 右にスクロール(&R) ウィンドウを右にスクロールします。\n右にスクロール



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

 次に、CScrollViewクラスのインスタンスを CMainFrameクラスのメンバ変数として宣言し、 WM_CREATEメッセージハンドラでCreate()を呼び出してビューウィンドウを作成します。

CMainFrameクラスのメッセージマップにはコマンドチェインを追加します。 これにより、メニューアイテムのWM_COMMANDメッセージがフレームウィンドウからビューウィンドウへ転送され、 さらにCScrollViewクラスの代替メッセージマップへのチェインによってCScrollWindowImplの代替メッセージマップに転送されます。 CScrollWindowImplでは間接的にDoScroll()というメンバ関数が呼び出され、 そこでメニューアイテムのID別にスクロール処理が行われます。

 最後に、SampleProject.cppファイルでMainFrm.hヘッダの前にView.hヘッダをインクルードします。