MFC教程(5)-- MFC对象的创建(2)
2010-03-25 20:33:44 来源:WEB开发网SDI应用程序对象的InitialInstance和SDI应用程序对象的InitialInstance比较,有以下的相同和不同之处。相同之处在于:
创建和添加模板;处理命令行。
不同之处在于:
创建的模板类型不同。SDI使用单文档模板,边框窗口类从CFrameWnd派生;MDI使用多文档模板,边框窗口类从CMDIChildWnd派生.
主窗口类型不同。SDI的是从CFrameWnd派生的类;MDI的是从CMDIFrameWnd派生的类。
主框架窗口的创建方式不同。SDI在创建或者打开文档时动态创建主窗口对象,然后加载主窗口(LoadFrame)并初始化;MDI使用第二部分的语句来创建动态主窗口对象和加载主窗口,第四部分语句显示、更新主窗口。
命令行处理的用途不一样。SDI一定要有命令行处理部分的代码,因为它导致了主窗口的创建;MDI可以去掉这部分代码,因为它的主窗口的创建、显示等由第二、四部分的语句来处理。
有别于SDI的主窗口加载过程
和SDI应用程序一样,MDI应用程序使用LoadFrame加载主边框窗口,但因为LoadFrame的虚拟属性,所以MDI调用了CMDIFrameWnd的LoadFrame函数,而不是CFrameWnd的LoadFrame。
LoadFrame的参数1指定了资源ID,其余几个参数取缺省值。和SDI相比,第四个创建上下文参数为NULL,因为MDI主窗口不需要文档、视等的动态创建信息。
图 5-17图解了CMdiFrameWnd::LoadFrame的流程:
首先,用同样的参数调用基类CFrameWnd的LoadFrame,其流程如图5-11所示,但由于参数4表示的创建上下文为空,所以,CFrameWnd::LoadFrame在加载了菜单和快捷键之后,给所有子窗口发送WM_INITUPDATE消息。
另外,WM_CREATE消息怎样处理呢?由于CMDIFrameWnd没有覆盖OnCreate,所以还是由基类CFrameWnd::OnCreate处理。但是它调用虚拟函数OnCreateClient(见图5-12)时,由于CMDIFrameWnd覆盖了该函数,所以动态约束的结果是CMDIFrameWnd::OnCreateClient被调用,它和基类的OnCreateClient不同,后者CreateView创建MFC视对象和视窗口,前者调用虚拟函数CreateClient创建MDI客户窗口。MDI客户窗口负责创建和管理MDI子窗口。
CreateClient是CMDIFrameWnd的虚拟函数,其原型如下:
BOOL CMDIFrameWnd::CreateClient(
LPCREATESTRUCT lpCreateStruct, CMenu* pWindowMenu);
该函数主要用来创建MDI客户区窗口。它使用Windows系统预定义的“mdiclient”窗口类来创建客户区窗口,保存该窗口句柄在CMDIFrameWnd的成员变量m_hWndMDIClient中。调用::CreateWindowEx创建客户窗口时传递给它的窗口创建数据参数(第11个参数)是一个CLIENTCREATESTRUCT结构类型的参数,该结构指定了一个菜单和一个子窗口ID:
typedef struct tagCLIENTCREATESTRUCT{
HMENU hWindowMenu;
UINT idFirstChild;
}CLIENTCREATESTRUCT;
hWindowMenu表示主边框窗口菜单栏上的“Windows弹出菜单项”的句柄。MDICLIENT类客户窗口在创建MDI子窗口时,把每一个子窗口的标题加在这个弹出菜单的底部。idFirstChild是第一个被创建的MDI子窗口的ID号,第二个MDI子窗口ID号为idFirstChild+1,依此类推。
这里,hWindowMenu的指定不是必须的,程序员可以在MDI子窗口激活时进行菜单的处理;idFirstChild的值是AFX_IDM_FIRST_MDICHILD。
综合地讲,CMDIFrameWnd::LoadFrame完成创建MDI主边框窗口和MDI客户区窗口的工作。
创建了MDI边框窗口和客户区窗口之后,接着是处理WM_INITUPDATE消息,进行初始化。但是按SDI应用程序的讨论顺序,下一节先讨论MDI子窗口的创建。
更多精彩
赞助商链接