第七章 Creating MDI Apps

图标

 

Creating MDI Apps

在 Multi-SDI 之前就有了 MDI , WTL 基于 CFramewindowImplBase基类提供了一系列相关类使得程序员编写 MDI 应用程序尤其的简单。Figure9 展示了 WTL 的 MDI 窗口架构.


Figure 9: MDI Windowing Hierarchy of WTL

继承链

 

CMDIWwindow 类是 MDI 应用程序的接口类, 继承自 CWindow 基类并添加了两个数据成员分别保存 MDI 客户区窗口句柄和 MDI 框架菜单句柄:
class CMDIWindow : public ATL::CWindow
{
public:
// Data members
    HWND m_hWndMDIClient;
    HMENU m_hMenu;
···
}
该类也封装了 MDI 窗口特有的 WM_MDIXXX 消息家族的发送处理请求, 以成员函数形式把相关功能提供给程序员使用, 成员函数命名为 MDIXXX().
MDI 应用程序由窗口框架, 管理 MDI 子窗口的框架客户区以及 MDI 子窗口组成.(如 Figure 10 所示)

Figure 10: MDI Application Consisting of Frame, Client Area, and MDI Children

MDI

 

为了创建 MDI 子窗口, 需要从 CMDIChildWindowImpl 类派生自己的窗口类.
class CChildFrame : public CMDIChildWindowImpl<CChildFrame> {

public:
    DECLARE_FRAME_WND_CLASS(NULL, IDR_MDICHILD)

    CHtmlView m_view;

    virtual void OnFinalMessage(HWND /*hWnd*/) {
        delete this;
    }

    BEGIN_MSG_MAP(CChildFrame)
        MESSAGE_HANDLER(WM_CREATE, OnCreate)
        CHAIN_MSG_MAP(CMDIChildWindowImpl<CChildFrame>)
    END_MSG_MAP()

    LRESULT OnCreate(UINT,WPARAM,LPARAM,BOOL&) {
        m_hWndClient = m_view.Create(m_hWnd, rcDefault,
_T("http://www.microsoft.com"),
WS_CHILD | WS_VISIBLE, WS_EX_CLIENTEDGE);

        bHandled = FALSE; // Let base class have a crack
        return 1;
    }
    …
};
MDI 子框架窗口与 SDI 框架窗口很相似(MDI 子框架窗口类一般命名为 CChildFrame). 比如, 通过传递菜单资源 ID 给 DECLARE_FRAME_WND_CLASS 宏来管理相关资源的创建, 正如在 SDI 框架窗口中所做的那样. 同样地, 我们在 WM_CREATE 消息映射函数中创建视图. 然而有所不同的是, 创建了视图之后, 必须设置 bHandled 为 FALSE, 因为我们需要 MDI 子窗口基类继续处理 WM_CREATE 消息.
LRESULT CChildFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
    bHandled = FALSE;
    ···
}
最后, 在虚拟函数 OnFinalMessage() 中, MDI 子框架窗口类对其自身调用 delete 操作符, 以此释放相关资源.
void CChildFrame::OnFinalMessage(HWND /*hWnd*/)
{
    delete this;
}

按照我们的设计, CMDIFrameWindowImpl 类作为所有 MDI 框架窗口类的基类, 实现了 MDI 框架和 MDI 客户区. 如下示例:
class CMainFrame : public CMDIFrameWindowImpl<CMainFrame> {
public:
    DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)
    BEGIN_MSG_MAP(CMainFrame)
        MESSAGE_HANDLER(WM_CREATE, OnCreate)
        COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
        COMMAND_ID_HANDLER(ID_WINDOW_CASCADE, OnWindowCascade)
        …
        CHAIN_MSG_MAP(CMDIFrameWindowImpl<CMainFrame>)
    END_MSG_MAP()

    LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&)
    {

        // Create command bar window, toolbar and statusbar
        …

        // Create MDI client   
        CreateMDIClient();
m_CmdBar.SetMDIClient(m_hWndMDIClient);
        …
        return 0;
    }

    LRESULT OnFileNew(WORD, WORD, HWND, BOOL&)
    {
            // Create MDI child
        CChildFrame* pChild = new CChildFrame;
        pChild->CreateEx(m_hWndMDIClient);
        return 0;
    }

    LRESULT OnWindowCascade(WORD,WORD,HWND, BOOL&)
    {
        MDICascade();
        return 0;
    }

};
在 WM_CREATE 消息映射函数中, 调用了基类 CMDIFrameWindowImpl 的成员函数 CreateMDIClient() 创建 MDI 客户区并设置 m_hWndMDIClient 数据成员. MDI 客户区是作为所有 MDI 子框架窗口的父窗口存在的. 而所有 MDI 子窗口都是在消息处理函数 OnFileNew() 中被创建的, 每个 MDI 子窗口都是 MDI 子窗口类的一个实例, 并且以 MDI 客户区作为其父窗口. 最后, 在 WinMain() 中我们创建 MDI 框架窗口, 这与 SDI 相似.

 

Divide and Conquer with Splitters

To be continued...  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值