65.9K
CodeProject 正在变化。 阅读更多。
Home

适用于 Windows Mobile 和桌面 WTL 应用程序的框架相关类和消息映射宏(第一部分)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (6投票s)

2009年7月29日

CPL

7分钟阅读

viewsIcon

37244

downloadIcon

1070

消息映射宏、拆分框架、全屏实现以及 UI 元素的自动映射。

FrameX1

引言

这是两篇关于用于 Windows Mobile 和桌面 WTL 应用程序的各种框架相关类和消息映射宏的文章中的第一篇。

第二部分将侧重于框架和窗格控件类中的多视图实现。

第一部分介绍了各种消息映射宏MDISDI 拆分框架类、一个全屏模式实现类,以及通过UI 元素的自动映射移除 WTL 的 UPDATE_UI_MAP

随附的 FrameX1.zip 中的 SDIFrameXMDISplitFrame 示例展示了将此代码包含到现有或新应用程序中的简单性。

两篇文章的可重用代码在 atlframx.zip 中。


消息映射宏

这些宏实现了消息应答和转发、条件消息映射链式调用以及在实现文件中定义消息映射。

  • MESSAGE_ANSWER(msg, res) 返回 res 并处理消息。在返回值 LRESULT 与上下文无关的情况下,它节省了一个函数调用,通常
  • MESSAGE_ANSWER(WM_ERASEBKGND, TRUE)
  • FORWARD_MESSAGE_WINDOW(msg, hWnd)msg 消息发送到提供的 hWnd 并处理消息。当命令应由未重绘的子控件执行时很有用。
  • FORWARD_MESSAGE(msg) 是 ATL FORWARD_NOTIFICATIONS() 宏的单一消息补充。它将 msg 消息发送到窗口并处理该消息。
  • CHAIN_MSG_MAP_CONDITION(bCondition, theChainClass)CHAIN_MSG_MAP_ALT_CONDITION(bCondition, theChainClass, msgMapID) 如果 bCondition 求值为 true,则执行 CHAIN_MSG_MAP()。当链式类处理取决于上下文时很有用。
  • CHAIN_MSG_MAP_CONDITION_MEMBER(bCondition, theChainMember)CHAIN_MSG_MAP_ALT_CONDITION_MEMBER(bCondition, theChainMember, msgMapID) 如果 bCondition 求值为 true,则与 CHAIN_MSG_MAP_MEMBER() 执行类似的操作。
  • .h 文件中声明消息映射并在 .cpp 文件中实现它可能有助于最小化重构依赖。在 MyClass.h 中单独使用 DECLARE_MSG_MAP(theClass),并在 MyClass.cpp 中你的消息映射声明的开头将 BEGIN_MSG_MAP() 替换为 IMPLEMENT_MSG_MAP(theClass)

拆分框架类

使用这些类消除了拆分框架布局中通常存在的中间 CSplitterWindow 和相关的消息流量。

CSplitFrameImplBase

CSplitFrameImplBase 直接派生自 TFrameImpl(本身派生自 WTL::CFrameWindowImplBase)和 WTL::CSplitterImpl。通过充分的 TFrameImpl 模板参数,它专门化为

  • CSplitFrameWindowImpl,一个即用型拆分框架基类。
  • CMDISplitFrameWindowImpl,一个即用型 MDI 拆分框架基类。
定义
template <class T, class TFrameImpl, bool t_bVertical = true>
class ATL_NO_VTABLE CSplitFrameImplBase : 
    public TFrameImpl,
    public CSplitterImpl<T, t_bVertical>
{
    typedef CSplitFrameImplBase<T, TFrameImpl, t_bVertical> thisClass;
public:
    typedef thisClass SplitFrame;
    typedef TFrameImpl Frame;
    typedef CSplitterImpl<T, t_bVertical> Splitter;
Overrides

CSplitFrameImplBase 在其构造函数中执行简单的拆分器初始化,并且不使用 WM_CREATE 消息。

// Splitter initialization in constructor
CSplitFrameImplBase()
{
#ifndef _WIN32_WCE
    m_cxySplitBar = ::GetSystemMetrics(t_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME);
    m_cxyMin = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
    ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0);
#else // CE specific
    m_cxyMin = m_cxySplitBar = 2 * ::GetSystemMetrics(t_bVertical ? 
SM_CXEDGE : SM_CYEDGE);
#endif // _WIN32_WCE
}

CSplitFrameImplBase 重写了 TFrameImpl::UpdateLayout()

void UpdateLayout(BOOL bResizeBars = TRUE)
{
        RECT rect;
        GetClientRect(&rect);

        // position bars and offset their dimensions
        UpdateBarsPosition(rect, bResizeBars);

        // resize splitter and children
        SetSplitterRect(&rect);
}

CSplitFrameWindowImpl

CSplitFrameWindowImpl 是一个 CSplitFrameImplBase,它使用 CFrameWindowImpl<T, ATL::CWindow> 作为 TFrameImpl 模板参数。

定义
template <class T, bool t_bVertical = true, class TBase = ATL::CWindow, 
    class TWinTraits = ATL::CFrameWinTraits>
class ATL_NO_VTABLE CSplitFrameWindowImpl : 
    public CSplitFrameImplBase<T, CFrameWindowImpl<T, TBase, TWinTraits>, t_bVertical>
{
    typedef CSplitFrameWindowImpl<T, t_bVertical, TBase, TWinTraits> thisClass;
};
用法

请参阅 SDIFrameX 示例中的 步骤 1

CMDISplitFrameWindowImpl

CMDISplitFrameWindowImpl 是一个即用型 MDI 拆分框架;它是 CSplitFrameImplBase,使用 CMDIFrameWindowImpl<T, WTL::CMDIWindow> 作为 TFrameImpl 模板参数。一个 bool t_bRightView 模板参数如果为 true(默认),则将 MDI 窗格设置为右侧(或底部)。

定义
template <class T, bool t_bRightView = true, bool t_bVertical = true, 
   class TBase = WTL::CMDIWindow, class TWinTraits = ATL::CFrameWinTraits>
class ATL_NO_VTABLE CMDISplitFrameWindowImpl : 
  public CSplitFrameImplBase<T, CMDIFrameWindowImpl<T, TBase, TWinTraits>, t_bVertical>
{
    typedef CMDISplitFrameWindowImpl<T, t_bRightView, t_bVertical, TBase, TWinTraits> 
        thisClass;
public:
    HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, 
        UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD)
    {
        HWND hWndMDIClient = Frame::CreateMDIClient(hWindowMenu, nID, nFirstChildID);
        SetSplitterPane(t_bRightView, hWndMDIClient);
        return hWndMDIClient;
    }

    BEGIN_MSG_MAP(thisClass)
        MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)
        CHAIN_MSG_MAP(SplitFrame)
    END_MSG_MAP()
};
Overrides

CMDISplitFrameWindowImpl 重写了 CMDIFrameWindowImpl::CreateMDIClient() 并根据 t_bRightView 设置拆分器的 MDI 窗格。

用法

请参阅 MDISplitFrame 示例。


CFullScreenImpl

CFullScreenImpl 管理任何弹出窗口(非子窗口)的全屏显示模式。最初用于框架窗口,它也可以应用于对话框或闪屏窗口。

CFullScreenImpl 不适用于 Windows CE,因为它已经在 atlwince.h 中包含了一个 CFullScreenFrame 类。

定义
template <class T, UINT t_uIdExitAccel = 0, bool t_bIsFrame = true>
class CFullScreenImpl
{
    typedef CFullScreenImpl<T, t_uIdExitAccel, t_bIsFrame> thisClass;
public:
    typedef thisClass FullScreen;

桌面全屏模式的一个设计问题是如何让用户有机会返回到正常窗口模式,因为全屏模式不再有菜单或工具栏。CFullScreenImpl 使用可选的 t_uIdExitAccel 加速器资源模板参数和一个 PreTranslateMessage 成员来帮助解决这个问题。第三个模板参数 t_bIsFrame,当 T 派生自 CFrameWindowImplBase 时设置为 true,然后管理工具栏和状态栏的可见性。

然后,当你开始迭代 2(这是构建迭代的开始)时,你可能想要复制测试用例并将它们重新分类到迭代 2。这还允许对测试用例进行粒度跟踪,并允许你说某个测试用例在一个迭代中是准备好的,但在另一个迭代中不是。同样,如何做到这一点取决于你以及你希望如何报告。 “场景”部分提供了更多细节。

默认构造函数从 t_uIdExitAccel 资源(如果提供了 t_uIdExitAccel)初始化 WINDOWPLACEMENT m_wp 成员和 CAccelerator m_ExitAccel 成员。

CFullScreenImpl() : m_bFullScreen(false), m_bTopVisible(false), m_bBottomVisible(false)
{
    m_wp.length = sizeof WINDOWPLACEMENT;
    if (t_uIdExitAccel)
        m_ExitAccel.LoadAccelerators(t_uIdExitAccel);
}
API
  • bool IsFullScreen() 返回全屏状态。
  • void SetExitAccelerator(BYTE fVirt, WORD key, WORD cmd) 根据参数将 CAccelerator m_ExitAccel 成员设置为单个按键。
  • void SetExitAccelerator(UINT uIdExitAccel)uIdExitAccel 加速器资源加载 CAccelerator m_ExitAccel 成员。
  • bool SetFullScreen(bool bFullScreen) 在全屏状态尚未设置且派生类 OnFullScreen(bFullScreen) 返回 true 时,根据 bFullScreen 设置全屏状态。如果全屏状态已更改,SetFullScreen() 返回 true,否则返回 false
  • bool SetFullScreen(bool bFullScreen)
    {
        if (bFullScreen == m_bFullScreen)
            return false;
    
        T* pT = static_cast<T*>(this);
        ATLASSERT(pT->IsWindow());
    
        if (!pT->OnFullScreen(bFullScreen))
            return false;
    
        if (bFullScreen)
        {
            // save current position
            pT->GetWindowPlacement(&m_wp);
    
            // remove framish styles
            pT->ModifyStyle(WS_CAPTION | WS_BORDER | WS_SYSMENU | 
                WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0, SWP_FRAMECHANGED);
    
            // hide bars if necessary
            if (t_bIsFrame)
            {
                m_bTopVisible = ::IsWindow(pT->m_hWndToolBar) && 
                    ::IsWindowVisible(pT->m_hWndToolBar);
    
                if (m_bTopVisible)
                    ::ShowWindow(pT->m_hWndToolBar, SW_HIDE);
    
                m_bBottomVisible = ::IsWindow(pT->m_hWndStatusBar) && 
                    ::IsWindowVisible(pT->m_hWndStatusBar);
    
                if (m_bBottomVisible)
                    ::ShowWindow(pT->m_hWndStatusBar, SW_HIDE);
            }
    
            // move to full screen
            CWindowDC dc(NULL);
            pT->SetWindowPos(NULL, 0, 0, 
                dc.GetDeviceCaps(HORZRES), dc.GetDeviceCaps(VERTRES),
                SWP_FRAMECHANGED);
    
        }
        else
        {
            // restore original styles
            pT->ModifyStyle(0, T::GetWndStyle(0), SWP_FRAMECHANGED);
    
            // restore bars
            if (t_bIsFrame)
            {
                if (m_bTopVisible)
                    ::ShowWindow(pT->m_hWndToolBar, SW_SHOW);
                if (m_bBottomVisible)
                    ::ShowWindow(pT->m_hWndStatusBar, SW_SHOW);
            }
    
            // move to saved position
            pT->SetWindowPlacement(&m_wp);
        }
        m_bFullScreen = bFullScreen;
    
        return true;
    }
  • BOOL PreTranslateMessage(MSG* pMsg) 在未处于全屏模式或 m_ExitAccel 未初始化时返回 FALSE;否则返回 m_ExitAccel.TranslateAccelerator() 的结果。
  • BOOL PreTranslateMessage(MSG* pMsg)
    {
        return !IsFullScreen() || m_ExitAccel.IsNull() ? 
            FALSE : m_ExitAccel.TranslateAccelerator(static_cast<T*>(this)->m_hWnd, pMsg);
    }
可重写
  • bool OnFullScreen(bool bFullScreen)SetFullScreen() 调用。默认的 CFullScreenImpl::OnFullScreen() 返回 true 以允许全屏模式更改。如果想防止更改或进行一些布局或 UI 更改,请在派生类中重写它。
用法

请参阅 SDIFrameX 示例中的 步骤 2


CAutoUpdateUI

CAutoUpdateUIWTL::CUpdateUI 的替代类,不需要派生的 UPDATE_UI_MAP。它在 UI 布局和 ID 尚未稳定的开发阶段很有用,并且以后可以方便地进行 UI 维护:添加、删除或重命名命令,或更改其托管工具栏、菜单或对话框。

如果派生类没有 UPDATE_UI_MAPCAutoUpdateUI 会嵌入一个空的 UPDATE_UI_MAP。派生或嵌入的 UPDATE_UI_MAP 通过调用 UIAddxxx 成员来填充。

定义
template <class T>
class CAutoUpdateUI : public WTL::CDynamicUpdateUI<T>
{
API
  • bool UIAddMenu(HMENU hm, bool bSetText = false) 将具有 hm 句柄的菜单及其子菜单添加到 UPDATE_UI_MAP
  • bool UIAddMenu(UINT uID, bool bSetText = false) 将具有 uID ID 的菜单资源及其子菜单添加到 UPDATE_UI_MAP

如果 bSetTexttrue,两者都会调用 UISetText() 来设置菜单项文本。

Overrides
  • bool UIAddToolBar(HWND hWndToolBar) 将具有 hWndToolBar HWND 的工具栏控件添加到 UPDATE_UI_MAP。如果工具栏包含嵌入式控件,则通过调用 UIAddChildWindowContainer() 将它们添加到 UPDATE_UI_MAP
  • 在 Windows CE 项目中,如果对菜单栏调用 UIAddToolBar(),它会进入无限循环,因此它被禁用。使用 #define _AUTOUI_CE_TOOLBAR 启用它,以便可以对其真正的工具栏控件调用。

  • bool UIAddChildWindowContainer(HWND hWnd)hWnd 窗口的直接子窗口添加到 UPDATE_UI_MAP。不会添加孙子窗口。
用法

请参阅 SDIFrameX 示例中的 步骤 3


SDIFrameX 示例

此示例详细介绍了从 WTL AppWizard 为 Explorer(拆分布局)应用程序生成的代码,实现一个派生自 CSplitFrameWindowImplCFullScreenImplCAutoUpdateUI 的框架的所有步骤。

步骤 0

  • SDIFrameX.cpp 中包含 #include "atlframx.h"
// SDIFrameX.cpp : main source file for SDIFrameX.exe
// ...
#include "..\atlframx.h" // 0

步骤 1:从 CSplitFrameWindowImpl 派生 CMainFrame 并移除中间的 CSplitterWindow

  • CSplitFrameWindowImpl 派生 CMainFrame
  • 使用 DECLARE_FRAME_WND_CLASS_EXCS_DBLCLKS 来启用双击拆分器条以均分窗格功能。
  • 移除 m_splitter 成员声明。
  • // MainFrm.h : interface of the CMainFrame class
    // ...
    class CMainFrame : 
        public CSplitFrameWindowImpl<CMainFrame>, // 1 
        // ...
    {
    public:
        DECLARE_FRAME_WND_CLASS_EX(NULL, IDR_MAINFRAME, CS_DBLCLKS, COLOR_WINDOW) // 1
    
        //CSplitterWindow m_splitter; // 1
    // ...
  • OnCreate()
    • 移除 m_splitter.Create() 调用。
    • m_panem_view 的父窗口更改为 m_hWnd
    • 移除对 CSplitterImpl 成员调用的 m_splitter. 前缀。
    LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, 
        BOOL& /*bHandled*/)
    {
        // ...
        //m_hWndClient = m_splitter.Create(m_hWnd, rcDefault, NULL, 
            //WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); // 1
        // ...
        m_pane.Create(/*m_splitter*/m_hWnd, _T("Tree"), 
            WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); // 1
        // ...
        m_view.Create(/*m_splitter*/m_hWnd, rcDefault, _T("http://www.microsoft.com"), 
            WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 
            WS_HSCROLL | WS_VSCROLL, WS_EX_CLIENTEDGE); // 1
    
        /*m_splitter.*/SetSplitterPanes(m_pane, m_view); // 1
        UpdateLayout();
        /*m_splitter.*/SetSplitterPosPct(25); // 1
  • OnViewTreePane()OnTreePaneClose() 中,移除对 CSplitterImpl 成员调用的 m_splitter. 前缀。
  • LRESULT OnViewTreePane(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, 
        BOOL& /*bHandled*/)
    {
        bool bShow = (/*m_splitter.*/GetSinglePaneMode() != SPLIT_PANE_NONE); // 1
        /*m_splitter.*/SetSinglePaneMode(bShow ? SPLIT_PANE_NONE : SPLIT_PANE_RIGHT); // 1
        UISetCheck(ID_VIEW_TREEPANE, bShow);
    
        return 0;
    }
    
    LRESULT OnTreePaneClose(WORD /*wNotifyCode*/, WORD /*wID*/, HWND hWndCtl, 
        BOOL& /*bHandled*/)
    {
        if(hWndCtl == m_pane.m_hWnd)
        {
            /*m_splitter.*/SetSinglePaneMode(SPLIT_PANE_RIGHT); // 1
            UISetCheck(ID_VIEW_TREEPANE, 0);
        }
    
        return 0;
    }
  • 编译、运行并检查拆分器功能。

步骤 2:实现一个由 Escape 键退出的全屏模式

  • resource.h 中声明一个 ID_VIEW_FULLSCREEN 标识符。
  • // resource.h
    // ...
    #define ID_VIEW_FULLSCREEN          0xE802 // 2
  • 添加一个全屏视图菜单项和一个 ID_VIEW_FULLSCREEN 加速器资源。
  • // Microsoft Visual C++ generated resource script.
    // SDIFrameX.rc
    // ...
    IDR_MAINFRAME MENU
    BEGIN
    // ...
        POPUP "&View"
        BEGIN
            MENUITEM "&Toolbar",                    ID_VIEW_TOOLBAR
            MENUITEM "&Status Bar",                 ID_VIEW_STATUS_BAR
            MENUITEM "Tree &Pane",                  ID_VIEW_TREEPANE
            MENUITEM "&Full Screen",                ID_VIEW_FULLSCREEN // 2
        END
    // ...
    
    
    // Accelerator
    // ...
    ID_VIEW_FULLSCREEN ACCELERATORS // 2
    BEGIN // 2
        VK_ESCAPE,      ID_VIEW_FULLSCREEN,     VIRTKEY, NOINVERT // 2
    END // 2
  • CFullScreenImpl 派生 CMainFrame
  • 添加一个 CMainFrame::OnFullScreen 成员以在全屏模式下隐藏左侧拆分窗格。
  • CMainFrame::PreTranslateMessage 调用 FullScreen::PreTranslateMessage 以在全屏模式下激活 ID_VIEW_FULLSCREEN 加速器。
  • // MainFrm.h : interface of the CMainFrame class
    // ...
    class CMainFrame :
        // ...
        public CFullScreenImpl<CMainFrame, ID_VIEW_FULLSCREEN>, // 2
       // …
    {
        // ...
        bool OnFullScreen(bool bFullScreen) // 2
        {
            if (bFullScreen) // 2
                SetSinglePaneMode(SPLIT_PANE_RIGHT); // 2
            else if (UIGetState(ID_VIEW_TREEPANE) & UPDUI_CHECKED) // 2
                SetSinglePaneMode(SPLIT_PANE_NONE); // 2
            return true; // allow change // 2
        }
    
        virtual BOOL PreTranslateMessage(MSG* pMsg)
        {
            if (FullScreen::PreTranslateMessage(pMsg)) // 2
                return TRUE; // 2
            // ...
  • 添加 ID_VIEW_FULLSCREEN 的命令处理程序。
  • // ...
    BEGIN_MSG_MAP(CMainFrame)
    // ...
        COMMAND_ID_HANDLER(ID_VIEW_FULLSCREEN, OnViewFullScreen) // 2
    // ...
    LRESULT OnViewFullScreen(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/,
        BOOL& /*bHandled*/) // 2
    {
        SetFullScreen(!IsFullScreen()); // 2
        return 0; // 2
    } // 2
  • 编译、运行并检查全屏实现。

步骤 3:从 CAutoUpdateUI 派生 CMainFrame 并移除 UPDATE_UI_MAP 宏

  • CAutoUpdateUI 派生 CMainFrame
  • 移除 UPDATE_UI_MAP 宏并在消息映射中链式调用 CAutoUpdateUI
  • CMainFrame::OnCreate() 中调用 UIAddMenu()
  • // MainFrm.h : interface of the CMainFrame class
    // ...
    class CMainFrame :
    // ...
        public CAutoUpdateUI<CMainFrame>, // 3  
    // ...
    {
    // ...
    /*    BEGIN_UPDATE_UI_MAP(CMainFrame) // 3
            UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
            UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
            UPDATE_ELEMENT(ID_VIEW_TREEPANE, UPDUI_MENUPOPUP)
        END_UPDATE_UI_MAP()*/ // 3
    // …
    
        BEGIN_MSG_MAP(CMainFrame)
        // ...
            CHAIN_MSG_MAP(CAutoUpdateUI<CMainFrame>) // 3
        // ...
    
    LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, 
                     LPARAM /*lParam*/, BOOL& /*bHandled*/)
    {
        UIAddMenu(IDR_MAINFRAME); // 3
    // ...
  • 编译、运行并检查 UpdateUI 实现。

MDISplitFrame 示例

此示例实现了一个基本的 MDI 拆分框架,合并了 WTL AppWizard 为 MDI 和 Explorer(拆分布局)应用程序生成的代码。

CMainFrame 派生自 CMDISplitFrameWindowImpl<CMainFrame>;添加了左侧窗格成员、命令处理程序,并将 ID_VIEW_TREEPANE 添加到菜单资源。

class CMainFrame :
   public CMDISplitFrameWindowImpl,
    public CUpdateUI,
    public CMessageFilter, public CIdleHandler
{
public:
    DECLARE_FRAME_WND_CLASS_EX(_T("WTL_MDISplitFrame"), IDR_MAINFRAME,
                               CS_DBLCLKS, COLOR_WINDOW)

    CPaneContainer m_pane;
    CTreeViewCtrl m_treeview;
    CMDICommandBarCtrl m_CmdBar;

    virtual BOOL PreTranslateMessage(MSG* pMsg)
    {
        if(Frame::PreTranslateMessage(pMsg))
            return TRUE;

        HWND hWnd = MDIGetActive();
        if(hWnd != NULL)
            return (BOOL)::SendMessage(hWnd, WM_FORWARDMSG, 0, (LPARAM)pMsg);

        return FALSE;
    }
// ...

BEGIN_UPDATE_UI_MAP(CMainFrame)
    UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
    UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
    UPDATE_ELEMENT(ID_VIEW_TREEPANE, UPDUI_MENUPOPUP)
END_UPDATE_UI_MAP()

BEGIN_MSG_MAP(CMainFrame)
    MESSAGE_HANDLER(WM_CREATE, OnCreate)
    MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
    COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
    COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
    COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
    COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
    COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
    COMMAND_ID_HANDLER(ID_VIEW_TREEPANE, OnViewTreePane)
    COMMAND_ID_HANDLER(ID_PANE_CLOSE, OnViewTreePane)
    COMMAND_ID_HANDLER(ID_WINDOW_CASCADE, OnWindowCascade)
    COMMAND_ID_HANDLER(ID_WINDOW_TILE_HORZ, OnWindowTile)
    COMMAND_ID_HANDLER(ID_WINDOW_ARRANGE, OnWindowArrangeIcons)
    CHAIN_MDI_CHILD_COMMANDS()       
    CHAIN_MSG_MAP(CUpdateUI)
    CHAIN_MSG_MAP(CMDISplitFrameWindowImpl)
END_MSG_MAP()

OnCreate() 成员创建左侧窗格,并调用重写的 CMDISplitFrameWindowImpl::CreateMDIClient(),该函数将右侧窗格设置为 CMDIWindow::m_hWndMDIClient

LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
    // create command bar window
    HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL,
             ATL_SIMPLE_CMDBAR_PANE_STYLE);
    // attach menu
    m_CmdBar.AttachMenu(GetMenu());
    // load command bar images
    m_CmdBar.LoadImages(IDR_MAINFRAME);
    // remove old menu
    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);

    CreateSimpleStatusBar();

    // Create left pane content
    m_pane.SetPaneContainerExtendedStyle(PANECNT_NOBORDER);
    m_pane.Create(m_hWnd, _T("Tree"), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
             WS_CLIPCHILDREN);
    m_treeview.Create(m_pane, rcDefault, NULL, WS_CHILD | WS_VISIBLE |
             WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TVS_HASLINES | TVS_LINESATROOT |
             TVS_HASBUTTONS | TVS_SHOWSELALWAYS, WS_EX_CLIENTEDGE);
    m_treeview.SetFont(AtlGetDefaultGuiFont());
    m_pane.SetClient(m_treeview);

    // Set left pane
    SetSplitterPane(SPLIT_PANE_LEFT, m_pane);
    UpdateLayout();
    SetSplitterPosPct(25);

    CreateMDIClient();
    m_CmdBar.SetMDIClient(m_hWndMDIClient);

    UIAddToolBar(hWndToolBar);
    UISetCheck(ID_VIEW_TOOLBAR, 1);
    UISetCheck(ID_VIEW_STATUS_BAR, 1);
    UISetCheck(ID_VIEW_TREEPANE, 1);

    // register object for message filtering and idle updates
    CMessageLoop* pLoop = _Module.GetMessageLoop();
    ATLASSERT(pLoop != NULL);
    pLoop->AddMessageFilter(this);
    pLoop->AddIdleHandler(this);

    return 0;
}

第一部分结论

第一部分介绍了对当前 WTL 8.0 框架管理和消息路由的一些简单增强。

第二部分将介绍多视图实现以及框架和窗格容器类的应用程序。

希望很快能见到你,祝好!

历史

  • 2009 年 7 月 29 日:首次发布。
© . All rights reserved.