MDI 创建

1 CilentWindow

1.1 CLIENTCREATESTRUCT

typedefstruct tagCLIENTCREATESTRUCT {

HANDLE hWindowMenu;

UINT  idFirstChild;

} CLIENTCREATESTRUCT, *LPCLIENTCREATESTRUCT;

<1>hWindowMenu  多文档应用窗口程序的菜单

<2>idFirstChild  指定第一个创建的MDI子窗口的ID,其后创建的MDI子窗口ID会在此基础上增加,并且随着窗口的销毁会重新分配ID。它们主要用在MDI子窗口向MDIFrame窗口中发送消息。

1.2 ClientWindow的创建

case  WM_CREATE:        // Create the client window

clientcreate.hWindowMenu      = hMenuInitWindow ;

clientcreate.idFirstChild         = IDM_FIRSTCHILD ;

hwndClient = CreateWindow( TEXT("MDICLIENT"), NULL, WS_CHILD |WS_CLIPCHILDREN |                                                     WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU)1,hInst, (PSTR)&clientcreate) ;

return 0 ;

2 MDI Window

2.1 MDICREATESTRUCT

typedef struct tagMDICREATESTRUCT {

LPCTSTR szClass;

LPCTSTR szTitle;

HANDLE  hOwner;

int     x;

int     y;

int     cx;

int     cy;

DWORD   style;

LPARAM  lParam;

} MDICREATESTRUCT,*LPMDICREATESTRUCT;

<1> hOwner 指创建MDI Client 窗口的hInstance

2.2 MDI child 窗口的创建

创建一个MDI child 窗口有三种方式

<1>通过向Client窗口发送WM_MDICREATE

case  IDM_FILE_NEWHELLO:  // Create a Hello child window

mdicreate.szClass     = szHelloClass;

mdicreate.szTitle       = TEXT ("Hello");

mdicreate.hOwner    = hInst ;

mdicreate.x         = CW_USEDEFAULT ;

mdicreate.y         = CW_USEDEFAULT ;

mdicreate.cx        = CW_USEDEFAULT ;

mdicreate.cy        = CW_USEDEFAULT ;

mdicreate.style     = 0 ;

mdicreate.lParam    = 0 ;

hwndChild =(HWND)SendMessage(hwndClient, WM_MDICREATE, 0, (LPARAM)                                                                       (LPMDICREATESTRUCT) &mdicreate) ;

return0 ;

<2>通过函数CreateMDIWindow

hwndChild=CreateMDIWindow(szHelloClass,TEXT("Hello"),0,CW_USEDEFAULT,

CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,hwndClient,hInst,NULL);

<3>通过函数CreateWindowEx

hwndChild =CreateWindowEx(WS_EX_MDICHILD,szHelloClass,TEXT ("Hello"),0,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,         ,hwndClient,hMenuInitWindow,hInst,NULL);

3 窗口消息处理

4 WM_MDIACTIVATE

发送方:

wParam

A handle to the MDI child window to beactivated.

lParam

This parameter is not used.

接受方:

wParam

A handle to the MDI child window beingdeactivated.

lParam

A handle to the MDI child window beingactivated.

通过跟踪消息可以发现在MDI child 窗口获得焦点以及失去焦点的时候,都会受到WM_MDIACTIVATE的消息。此时的lParam = NULL。

当子窗口获取焦点的时候,Client  Window 会受到WM_GETACTIVE的消息。

5 WM_QUERYENDSESSION

当用户选择结束会话(session)的或者应用程序调用系统关闭函数的时候,就会发送WM_QUERYSESSION消息。当应用程序返回0 ,会话不会被终止。

wParam

This parameter is reserved for futureuse.

lParam

This parameter can be one or more of thefollowing values. If this parameter is 0, the system is shutting down orrestarting (it is not possible to determine which event is occurring).

<1>用户注销的方法

ExitWindows(0, 0);

或者

ExitWindowsEx(EWX_LOGOFF, 0);

这个时候一般会出现提示对话框

case  WM_QUERYENDSESSION:

nOff =      MessageBox(NULL,(LPCWSTR)L"Endsession?",(LPCWSTR)L"WM_QUERYENDSESSION",

MB_YESNO);

// ReturnTRUE to continue, FALSE to stop.

returnnOff == IDYES;

break;

<2> 用户重启

ExitWindowsEx(EWX_REBOOT,0);

<3> 用户关机

ExitWindowsEx(EWX_SHUTDOWN,0);

6 MDI窗口类别

一个MDI窗口应用程序包含三种窗口,Frame Window,Client Window ,Child Window。

Frame Window: 类似主窗口,它包含标题栏,菜单栏,边框,最小最大化按钮。

MDI Client Window: 属于已经注册好的窗口类,MDICLIENT,它是FrameWindow的子窗口,也是Child Window 的背景,对子窗口的操作也是通过Client Window 实现的。

Child Window :它是Client Window的子窗口。每个子窗口都有一个边框,标题栏,系统菜单,最小最大化按钮。Child Window 不能被拖到Client Window的外面。

7 MDI APP的菜单

MDI应用程序的菜单是属于FrameWindow的。即便通过

SendMessage(hwndClient, WM_MDISETMENU,(WPARAM)hMenuHello, (LPARAM) hMenuHelloWindow) ;

这样的Client Window 设置的菜单,它就是属于Frame Window的,所以在设计MDI的菜单的时候要注意:

<1> 应该设计多个菜单,Frame Window初始化菜单,各个子窗口打开时的专属菜单。

<2> 各个子窗口都要用到的菜单命令处理应该放在FrameWindow的窗口过程函数中,分属于子窗口独自的就放在子窗口对应的窗口过程函数中。

<3> Frame Window的菜单项中应该只包含新文档窗口的创建,以及整个APP 的关闭的菜单项。

7.2 关于Window Menu:

MSDN上的解释是:

The frame window of an MDI applicationshould include a menu bar with a window menu. The window menu should includeitems that arrange the child windows within the client window or that close allchild windows.

翻译:多文档应用程序的框架窗口应该包含一个带有窗口菜单的菜单栏。窗口才到那应该包含组织客户区窗口内子窗口的菜单项,或者关闭所有的子窗口。

可见:Window Menu指的是主要处理MDI多个子窗口之间排列组合以及关闭的菜单,它并不是什么特别的专业术语。

那么Window Menu 起初是怎么指定的呢?

我们要重新回到CLIENTCREATESTRUCT结构体中,

typedef struct tagCLIENTCREATESTRUCT {
    HANDLE hWindowMenu; 
    UINT   idFirstChild; 

} CLIENTCREATESTRUCT,*LPCLIENTCREATESTRUCT;

其中 hWindowMenu的解释是:

Handle to the MDI application's windowmenu. An MDI application can retrieve this handle from the menu of the MDIframe window by using the GetSubMenufunction.

讲到这里,一切都清晰明了很多了。

7.3 关于 WM_MDISETMENU

这个子窗口发给Client窗口让其修改Frame Window的整个菜单或者 Window Menu的消息。

SendMessage (hwndClient,WM_MDISETMENU,(WPARAM)hMenuHello, (LPARAM)hMenuHelloWindow) ;

其中的wParam参数代表修改FrameWindow的 整个菜单,lParam参数代表修改Frame Window的WindowMenu。

hMenuHello菜单如下所示:

现在我们进行测试,观察不同参数下的不同效果:

<1> lParam 参数为NULL,wParam 不为NULL的时候:

我们观察到的3个弹出菜单:

<2> 两个参数都不为空的时候

并且令hMenuHelloWindow    = GetSubMenu(hMenuHello,  2) ;

得到的结果如下所示:

令hMenuHelloWindow   = GetSubMenu(hMenuHello,  1) ;

<3> 当wParam为空,lParam不为空的时候

没有打开新的文档的时候,Frame Window的界面如下所示:

SendMessage(hwndClient,WM_MDISETMENU,NULL, (LPARAM) hMenuHelloWindow) ;

利用上面语句改变Frame Window的菜单后,如下所示:

当我们改变初始菜单中 Help 和File的顺序的时候:

<4> wParam ,lParam参数都为NULL的时候:

Window Menu 会被变成NULL,即便此后重新设置也无法改变。

总结:

1 创建MDI窗口程序,首先要创建一个FrameWindow,然后在WM_CREATE消息中创建Client Window。

2 在WM_COMMAND命令中创建 MDI Child Window。

3 在Frame Window的窗口过程函数中,处理各个子窗口的共同命令消息,对于某个窗口的个例消息,交给此窗口的过程函数进行处理。

4 在产生子窗口的时候,通常要改变主窗口的菜单。

程序下载地址: MDI源码

Windows编程之MDI相关推荐

  1. windows编程之GDI绘图 -- 实验3-1

    windows编程之GDI绘图 – 实验3-1 文章目录 windows编程之GDI绘图 -- 实验3-1 @[toc] 1.实验名称 2.实验目的 3.实验的步骤和方法 4.代码实现 5.思考题 6 ...

  2. Windows编程之CreateEvent,WaitForSingleObject,SetEvent,ResetEvent函数

    一 Windows编程之CreateEvent,WaitForSingleObject,SetEvent,ResetEvent函数 1 CreateEvent HANDLE WINAPI Create ...

  3. windows编程之TextOut与DrawText -- 文本输出实验

    文章目录 windows编程之TextOut与DrawText -- 文本输出实验 实验名称 实验目的 实验要求 实验源码 思考题 windows编程之TextOut与DrawText – 文本输出实 ...

  4. windows编程之TextOut与DrawText

    文章目录 windows编程之TextOut与DrawText TextOut 是什么函数 TextOut 函数原型 DrawText 是什么函数 DrawText 函数原型 TextOut与Draw ...

  5. 【转】Windows编程之hdc和hwnd的区别

    在windows编程中类型名前面加H的基本是句柄 常用句柄 : HBITMAP 保存位图信息的内存域的句柄 HBRUSH 画刷句柄 HCTR 子窗口控件句柄 HCURSOR 鼠标光标句柄 HDC 设备 ...

  6. windows编程之GDI基础--设备内容(二)

    取得设备内容句柄: Windows提供了几种取得设备内容句柄的方法.如果在处理一个消息时取得了设备内容句柄,应该在退出窗口函数之前释放它(或者删除它).一旦释放了句柄,它就不再有效了. 在WM_PAI ...

  7. Windows编程之Window介绍

    最近在学习windows编程,本来想写个总结.可发现仅仅 3 天没碰代码,记忆就淡了.话说这个记忆力可能提前奔三了.所以依旧用复习的老办法,再看一遍官方文档,翻译,并且记录. 先来介绍下什么是wind ...

  8. windows编程之Windows Shell 编程

    这里仅仅是记录下该资源,推荐到下文列出的连接进行查看 用VC++ 进行Windows Shell 扩展编成 由ccc编译 序言: 看过一些对windows 外壳的扩展程序,在使用上一般都是直接利用wi ...

  9. windows编程之WM_MENUSELECT消息

    WM_MENUSELECT消息: (1) 程序窗口如下所示: (2)程序中的消息处理如下所示: LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, ...

最新文章

  1. sql server和mysql分页查询_sql server和mysql中分别实现分页功能
  2. 分布式动态配置后浪推前浪 -- Nacos
  3. 「学习笔记」多项式相关
  4. 2021-05-08 docker镜像无法删除 Error:No such image:xxxxxx
  5. PostgreSQL GIN multi-key search 优化
  6. GitHub/Git 使用
  7. 51 nod 1624 取余最长路 思路:前缀和 + STL(set)二分查找
  8. 用 C# 来守护 Python 进程
  9. 改造create-react-app 通过npm命令动态打包文件
  10. 计算机算法基础总结(借鉴、整理)
  11. 日志分析工具、日志管理系统、syslog分析
  12. 换个角度看发国难财的行为
  13. 群赛 round#5 解题报告(superoxide,choice,rpwt)
  14. C#下对PDF文件进行电子图片签名
  15. 用 mkcert 搭建本地开发受信 HTTPS 证书环境
  16. 通知与服务——服务Service——服务的绑定与解绑延迟绑定服务与解绑服务
  17. 2.* 版本taro引入 taro-ui编译小程序阶段报错, Module not found: Can‘t resolve ‘./style/index.scss‘
  18. freeSWITCH + WebRTC 音视频会议
  19. Linux驱动|rtc-hym8563移植笔记
  20. 低成本VR手套Lucid再升级,利用柔性齿条来提升手势追踪

热门文章

  1. 计算机毕业设计JAVA大学生健康信息管理系统mybatis+源码+调试部署+系统+数据库+lw
  2. 推荐几部以程序员为主角影视剧
  3. 【程序化天空盒】过程记录02:云扰动 边缘光 消散效果
  4. python将微信二维码转化为炫酷二维码
  5. OCJP Oracle认证Java程序员考试题库分享
  6. PICT工具安装使用
  7. JQuery表单序列化方式
  8. NPM、NVM、NRM
  9. 一日三餐如何吃?(减肥篇)
  10. mlc颗粒的m.2固态有哪些(多款MLC企业级SSD性能实测)