您的位置:首页 > 其它

MFC技术系列(四)--Frame窗口(2)

2007-07-26 23:21 323 查看
接上篇, "Frame窗口(1)"

3. MDI

这是MFC提供的另一个复杂的Doc-View框架。它由CDocument, CView的派生类和CMDIChildWnd(winmdi.cpp)的派生类(Frame Window)构成一类Frame窗口,这些类的RUNTIMECLASS宏信息由CMultiDocTemplate类(docmulti.cpp)管理,并同样注册到CDocManager类。同SDI一样,这些运行时类信息也是由前面提到的一对宏来管理的。
MFC还提供了一个容纳这些子Frame窗口的父Frame窗口基类:CMDIFrameWnd类(winmdi.cpp)。对于MDI应用,其Top-level窗口即为该类的派生类。
MDI创建一个View的过程如下:
1. 如果是点击New菜单项(刚启动时默认打开该菜单FileNew),那么从App类进入到CDocManager的OnFileNew方法。该方法中,如果注册的Document类型不只一个,那么会弹出CNewTypeDlg,选择一种Document。然后进入到下一步。如果要改写该默认行为,那么可以自己编写OnFileNew的响应逻辑,而不是调用基类CWinApp的响应方法。
2. 既然是MDI,那么执行CMultiDocTemplate的OpenDocumentFile虚方法。同SDI一样,该方法也是创建过程的核心方法。其实,既然从一个DocTemplate来看,这里面的基本过程基本同SDI。即:先调用CreateNewDocument创建Document,然后调用CreateNewFrame创建子Frame窗口,然后,如果是创建一个空文档,那么调用Document类的OnNewDocument虚方法,如果是打开一个已有文档,那么调用OnOpenDocument虚方法。在CreateNewFrame过程中,将调用CreateView方法创建对应的View窗口
3. CreateNewFrame方法中,将调用LoadFrame装载子Frame窗口。此时,有两个重要的成员,即:m_hMenuShared和m_hAccelTable,分别为子Frame窗口的菜单和加速键表。它们从对应的MultiDocTemplate实例中获得(doc template构造的第一个参数即为Frame资源ID)。注意,在MFC框架中,为能够减少代码,将Frame窗口的Title图标、菜单和加速键的资源ID都规定为同一个值(既然这些资源的类型(RT值)不同,所以不用担心会被互相覆盖)
4. 最后,调用InitUpdateFrame。具体描述参见SDI部分

MFC的上述两个MDI窗口类都是对WM_MDI系列消息的封装。如下几点需要特别注意:
1. CMDIChildWnd的父窗口为一个被称为MDI client的窗口。当你将所有子Frame窗口关闭后,位于空白区域的就是该窗口。该窗口的父窗口才是CMDIFrameWnd窗口
2. 关于子Frame窗口的消息,都是发送到这个MDI client窗口。它其实是child frame窗口和main frame窗口之间的纽带。可以直接通过main frame窗口的m_hWndMDIClient公有成员获得该窗口的句柄
3. 基于DocTemplate,通过注册不同的文档模板,我们很容易创建出相同document的不同view,它们实际由不同的child frame窗口容纳。如果要在自己的代码中创建一个child frame窗口,那么完全可以参考上面过程的主要方法。

MDI各个主要场景下,消息序列:
1. 创建一个child frame
<00001> 000301DC S WM_MDICREATE lpmdic:0012F18C

<00002> 000301DC R WM_MDICREATE hwndChild:000F0546

<00003> 000301DC S WM_MDISETMENU hmenuFrame:000504E7 hmenuWindow:000804B5

<00004> 000301DC R WM_MDISETMENU hmenuFrameOld:000704DF

<00005> 000301DC S WM_MDIREFRESHMENU

<00006> 000301DC R WM_MDIREFRESHMENU hmenuFrame:000504E7

2. 关闭一个child frame
<00001> 000301DC S WM_MDIDESTROY hwndChild:000F0546

<00002> 000301DC S WM_MDISETMENU hmenuFrame:000704DF hmenuWindow:00000000

<00003> 000301DC R WM_MDISETMENU hmenuFrameOld:000504E7

<00004> 000301DC S WM_MDIREFRESHMENU

<00005> 000301DC R WM_MDIREFRESHMENU hmenuFrame:000704DF

<00006> 000301DC R WM_MDIDESTROY

3. 子frame窗口的排列
层叠:WM_MDICASCADE
平铺:WM_MDITILE
排列图标:WM_MDIICONARRANGE
4. 从菜单上选择背后的某个子frame窗口,此时,当前子Frame窗口将被切换到另一个子Frame窗口(从spy结果来看,如果是直接使用鼠标选中某个子Frame,则不会产生WM_MDIACTIVATE消息)
<00001> 000301DC S WM_MDIACTIVATE hwndChildActivate:0036067E

<00002> 000301DC S WM_MDIREFRESHMENU

<00003> 000301DC R WM_MDIREFRESHMENU hmenuFrame:000504E7

<00004> 000301DC S WM_MDISETMENU hmenuFrame:000504E7 hmenuWindow:000804B5

<00005> 000301DC R WM_MDISETMENU hmenuFrameOld:000504E7

<00006> 000301DC R WM_MDIACTIVATE

5. 在子Frame窗口的系统菜单中选择“下一个”
<00001> 000301DC S WM_MDINEXT hwndChild:0036067E fNext:False

<00002> 000301DC S WM_MDIREFRESHMENU

<00003> 000301DC R WM_MDIREFRESHMENU hmenuFrame:000504E7

<00004> 000301DC S WM_MDISETMENU hmenuFrame:000504E7 hmenuWindow:000804B5

<00005> 000301DC R WM_MDISETMENU hmenuFrameOld:000504E7

<00006> 000301DC R WM_MDINEXT

6. 子frame窗口被最小化(??)
7. 子frame窗口被最大化(WM_MDIMAXIMIZE)(不过使用spy++未捕获到该消息)
8. 子frame窗口从最小化,或者最大化状态恢复(WM_MDIRESTORE)(不过使用spy++未捕获到该消息)

可以看出,几乎每一个涉及到菜单状态的行为发生过程中,基本都是菜单的切换。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: