MDI的元素
一个主窗口,包括标题栏、工具栏、菜单栏、系统菜单图标、可拉伸边框、最大最小化按钮、客户区。客户区不直接显示输出,而是有0个或多个子窗口,每个子窗口显示一个文档。
子窗口很像主窗口,只是没有菜单栏。在同 一时刻只有一个子窗口是激活的。
MDI看起来用子窗口可以实现,但当研究一下现有的MDI应用程序,就会发现实现起来需要复杂的编码。
MDI接口
Windows 98 MDI包括一个窗口类、五个函数、两个结构体和十二个消息。
窗口类:MDICLIENT
结构体:CLIENTCREATESTRUCT、MDICREATESTRUCT
函数:DefFrameFroc、DefMDIChildProc、TranslateMDISysAccel、ArrangeIconicWindows、CreateMDIWindow
消息:WM_MDI打头
使用CreateWindow创建客户区窗口,第一个参数,即窗口类为MDICLIENT,最后一个参数必须是指向CLIENTCREATESTRUCT结构体变量的指针,CLIENTCREATESTRUCT有两个字段:hWindowMenu和idFirstChild。hWindowMenu是文档列表菜单项加载所在的子菜单,idFirstChild是子窗口的第一个ID号,这个ID应该大于其他所有的菜单ID。
TranslateMDISysAccel与TranslateAccelerator用法类似,它把MDI对应的快捷键转化为WM_SYSCOMMAND消息,但前者的窗口名柄参数是客户窗口句柄,后者是主窗口句柄。
创建MDI窗口,先初始化MDICREATESTRUCT结构体变量,再向客户窗口发送WM_MDICREATE消息(MDICREATESTRUCT变量指针做LPARAM)或者调用CreateMDIWindow函数。MDICREATESTRUCT的szTitle字段一般赋为对应的文件名,style可以赋WS_HSCROLL、WS_VSCROLL、WS_MINIMIZE等,lParam是主窗口与子窗口(文档窗口)共享一些变量的方法。子窗口的WM_CREATE消息的lParam是一个CREATESTRUCT指针,它的lpCreateParams字段是指向创建该窗口时使用的MDICREATESTRUCT变量的指针。当客户窗口收到WM_MDICREATE,会创建一个子窗口并在文档列表菜单(CLIENTCREATESTRUCT::hWindowMenu)后加入最新的窗口名(MDICREATESTRUCT指定的)。
通过向客户窗口发送WM_MDIGETACTIVE消息可获得焦点窗口的句柄。发送WM_MDIDESTROY可以关闭子窗口。
向客户窗口发送WM_MDITILE、WM_MDICASCADE和WM_MDIICONARRANGE可以排列窗口。
所有没被处理的消息都要用DefFrameProc函数处理,即使主窗口处理了WM_MENUCHAR、WM_SETFOCUS和WM_SIZE消息,这些消息也要给DefFrameProc处理。
EnumChildWindows(hwndClient,EnumProc,0):对hwndClient所有的子窗口用EnumProc处理,EnumProc定义为 BOOL CALLBACK EnumProc(HWND hwnd,LPARAM lParam),hwnd是子窗口句柄。
当子窗口变为活动窗口或由活动窗口变为非活动窗口,都会收到WM_MDIACTIVATE消息,wParam和lParam分别是取消活动窗口和设为活动窗口的窗口句柄。在WM_MDIACTIVATE消息中,可以修改主窗口菜单,在MDI中修改菜单通过给客户窗口发WM_MDISETMENU消息,而不是调用SetMenu函数。
子窗口消息处理过程中未被处理的消息必须交由DefMDIChildProc函数处理,而不是DefWindowProc。WM_CHILDACTIVATE、WM_geTMINMAXINFO、WM_MENUCHAR、WM_MOVE、WM_SETFOCUS、WM_SIZE和WM_SYSCOMMAND必须由DefMDIChildProc处理。