VS2015之博大精深的MFC项目开发(一)

VS2015之博大精深的MFC项目开发(一)

  • 第一章 MFC基础篇
    • 1、MFC01-2:Win32程序资源管理
      • 1.1 讲解MessageBox(在windows中如何输出)
      • 1.2 给我们的软件插入一个图标
      • 1.3 对话框程序是如何建立的(在windows中如何输入)
    • 2、MFC01-3:基于对话框的Win32程序开发
      • 2.1 如何在对话框中实现输入、实现关闭呢
    • 3、MFC02-1:四则运算的Win32程序开发
      • 3.1 添加菜单
      • 3.2 Dialog消息处理函数中的返回值
      • 3.3 让四则运算支持double类型
      • 3.4 格式化函数
    • 4、MFC02-2:Windows消息处理机制
      • 4.1 windows消息列表
      • 4.2 测试其他的消息种类
    • 5、MFC02-3:Windows类型介绍
      • 5.1 windows的变量类型
        • 解析DECLARE_HANDLE宏
      • 5.2 简介MFC开发
      • 用MFC开发四则运算计算器程序
    • 6、MFC03-1:Win32程序界面权限登录开发
      • 6.1 实现对话框启动后居中显示
      • 6.2 实现登录界面
    • 7、MFC03-2:MFC架构与原理分析1
      • 7.1 完成登录对话框居中显示,用户名密码匹配
      • 7.2 编辑控件的属性
      • 7.3 测试各种windows消息
      • 7.4 用MFC开发计算器
    • 8、MFC03-3:MFC架构与原理分析2
      • 8.1 把原始的Win32程序改造为MFC程序
    • 9、MFC04-1:用MFC应用程序向导建立MFC工程
      • 9.1 简介MFC六大关键技术
      • 9.2 UNICODE编码简介
    • 10、MFC04-2:UNICODE编码的应用
      • 10.1 TCHAR
      • 10.2 Unicode与多字符集字符串互相转换
      • 10.3 MultiByteToWideChar函数
    • 11、MFC04-3:Unicode与多字符集字符串互相转换
      • 11.1 WideCharToMultiByte函数
      • 11.2 在窗口上实时显示当前时间
      • 11.3 封装一个自己的CRect类
      • 11.4 屏幕坐标系和窗口坐标系
    • 12、MFC05-1:MFC的六大关键技术
      • 12.1 MFC的六大关键技术都有哪些
      • 12.2 浅谈消息映射机制
      • 12.3 再谈屏幕坐标系和窗口坐标系
    • 13、MFC05-2:MFC基础变量类型
      • 13.1 模仿开发CPoint类
      • 13.2 封装CRect类
    • 14、MFC05-3:简单MFC程序设计
      • 14.1 继续模拟CRect类的常用成员函数
        • 函数CenterPoint的实现
        • 函数IsRectEmpty和IsRectNull的实现
        • 函数InflateRect和函数DeflateRect的实现
        • 演示一下NormalizeRect函数的功能
      • 14.2 继续完善计算器程序


第一章 MFC基础篇

1、MFC01-2:Win32程序资源管理

VS2015之博大精深的MFC项目开发(一)_第1张图片
VS2015之博大精深的MFC项目开发(一)_第2张图片

VS2015之博大精深的MFC项目开发(一)_第3张图片

VS2015之博大精深的MFC项目开发(一)_第4张图片


1.1 讲解MessageBox(在windows中如何输出)

VS2015之博大精深的MFC项目开发(一)_第5张图片
VS2015之博大精深的MFC项目开发(一)_第6张图片

VS2015之博大精深的MFC项目开发(一)_第7张图片
VS2015之博大精深的MFC项目开发(一)_第8张图片


1.2 给我们的软件插入一个图标

VS2015之博大精深的MFC项目开发(一)_第9张图片

把多余不需要的尺寸大小的图标删除掉,然后打开外部编辑器对图标进行编辑:
VS2015之博大精深的MFC项目开发(一)_第10张图片

VS2015之博大精深的MFC项目开发(一)_第11张图片

如上图所示,我们自己编辑的图标很难看,我们可以导入一个现成的图标:
VS2015之博大精深的MFC项目开发(一)_第12张图片

把找到的图标粘贴在自己这个项目的目录下,然后再导入这个图标:
VS2015之博大精深的MFC项目开发(一)_第13张图片

VS2015之博大精深的MFC项目开发(一)_第14张图片

在这里插入图片描述

我们发现图标没有变化,这是怎么回事呢?
因为还有一个旧的图标(IDI_ICON1)在资源里面,如果工程里有不止一个图标,它会缺省选第一个图标去插入,也就是ID最小的图标作为应用程序的图标
VS2015之博大精深的MFC项目开发(一)_第15张图片

所以,我们把IDI_ICON1这个图标资源给删掉,重新编译生成,如果目录中该exe文件的图标还没有发生变化,把它拷贝到外面也许就变了,可能这是由于windows系统还没识别出来。


1.3 对话框程序是如何建立的(在windows中如何输入)

VS2015之博大精深的MFC项目开发(一)_第16张图片

VS2015之博大精深的MFC项目开发(一)_第17张图片

在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第18张图片

VS2015之博大精深的MFC项目开发(一)_第19张图片
VS2015之博大精深的MFC项目开发(一)_第20张图片

VS2015之博大精深的MFC项目开发(一)_第21张图片

VS2015之博大精深的MFC项目开发(一)_第22张图片

VS2015之博大精深的MFC项目开发(一)_第23张图片

VS2015之博大精深的MFC项目开发(一)_第24张图片
VS2015之博大精深的MFC项目开发(一)_第25张图片

VS2015之博大精深的MFC项目开发(一)_第26张图片

VS2015之博大精深的MFC项目开发(一)_第27张图片

VS2015之博大精深的MFC项目开发(一)_第28张图片

VS2015之博大精深的MFC项目开发(一)_第29张图片


2、MFC01-3:基于对话框的Win32程序开发

2.1 如何在对话框中实现输入、实现关闭呢

VS2015之博大精深的MFC项目开发(一)_第30张图片

VS2015之博大精深的MFC项目开发(一)_第31张图片

VS2015之博大精深的MFC项目开发(一)_第32张图片

VS2015之博大精深的MFC项目开发(一)_第33张图片

VS2015之博大精深的MFC项目开发(一)_第34张图片

VS2015之博大精深的MFC项目开发(一)_第35张图片

VS2015之博大精深的MFC项目开发(一)_第36张图片

VS2015之博大精深的MFC项目开发(一)_第37张图片

VS2015之博大精深的MFC项目开发(一)_第38张图片

IDCANCEL和IDOK都是系统的按钮,你按ESC或者Alt+F4或者右上角关闭按钮,都会走IDCANCEL这条通道;
你在某个编辑框中,按回车键的话,系统会默认你点击的是IDOK这个缺省按钮。

VS2015之博大精深的MFC项目开发(一)_第39张图片

VS2015之博大精深的MFC项目开发(一)_第40张图片

VS2015之博大精深的MFC项目开发(一)_第41张图片

VS2015之博大精深的MFC项目开发(一)_第42张图片

上述这两个函数的最后一个参数,意思是否支持负数(signed和unsigned)。

VS2015之博大精深的MFC项目开发(一)_第43张图片

VS2015之博大精深的MFC项目开发(一)_第44张图片


3、MFC02-1:四则运算的Win32程序开发

VS2015之博大精深的MFC项目开发(一)_第45张图片

VS2015之博大精深的MFC项目开发(一)_第46张图片

我们给对话框插入一个位图,在工具栏里有一个图片控件:
VS2015之博大精深的MFC项目开发(一)_第47张图片
VS2015之博大精深的MFC项目开发(一)_第48张图片

VS2015之博大精深的MFC项目开发(一)_第49张图片

VS2015之博大精深的MFC项目开发(一)_第50张图片

在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第51张图片


3.1 添加菜单

VS2015之博大精深的MFC项目开发(一)_第52张图片

VS2015之博大精深的MFC项目开发(一)_第53张图片

VS2015之博大精深的MFC项目开发(一)_第54张图片

只是用来显示、弹出的菜单项(例如上图的系统)它的属性Popup是True,我只负责弹出,我并不负责执行命令;
而真实的菜单项(例如退出)它的Popup是False,它是会执行命令的,也就是说它会执行消息传递的。

还可以给菜单添加快捷键:
VS2015之博大精深的MFC项目开发(一)_第55张图片

VS2015之博大精深的MFC项目开发(一)_第56张图片

VS2015之博大精深的MFC项目开发(一)_第57张图片

VS2015之博大精深的MFC项目开发(一)_第58张图片

编译运行这个软件,结果我们发现没有这个菜单,我们要设置一下对话框的属性,选择这个菜单:

VS2015之博大精深的MFC项目开发(一)_第59张图片

VS2015之博大精深的MFC项目开发(一)_第60张图片

VS2015之博大精深的MFC项目开发(一)_第61张图片


3.2 Dialog消息处理函数中的返回值

VS2015之博大精深的MFC项目开发(一)_第62张图片

就是说你在编程的时候,已经对这个消息处理好了,不需要系统在管了,你就return TRUE;
缺省的时候有很多不需要你去处理的消息,就可以return FALSE,让系统去处理。

VS2015之博大精深的MFC项目开发(一)_第63张图片
返回TRUE就是说我都做好了,系统你就别再管了,哪个按钮处理好了,你就在那个按钮的地方返回TRUE;
凡是你处理过的你就return TRUE;
返回FALSE,就是说编程的人没有对这个按钮做任何的处理,让系统代劳,执行对话框默认的消息处理函数。

VS2015之博大精深的MFC项目开发(一)_第64张图片

凡是你处理过的地方就返回TRUE,没有处理过的缺省都要返回FALSE。

VS2015之博大精深的MFC项目开发(一)_第65张图片

VS2015之博大精深的MFC项目开发(一)_第66张图片

VS2015之博大精深的MFC项目开发(一)_第67张图片

VS2015之博大精深的MFC项目开发(一)_第68张图片

VS2015之博大精深的MFC项目开发(一)_第69张图片

如果你进行除零操作,软件就会崩溃:
VS2015之博大精深的MFC项目开发(一)_第70张图片

所以我们要对输入的数据进行校验:
在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第71张图片


3.3 让四则运算支持double类型

VS2015之博大精深的MFC项目开发(一)_第72张图片

VS2015之博大精深的MFC项目开发(一)_第73张图片

VS2015之博大精深的MFC项目开发(一)_第74张图片

C语言有将整数转换为字符串的函数itoa,但是它没有将浮点数转换为字符串的函数,那怎么办呢?
C语言是用什么函数来将各种类型的数字转为字符串的呢?


3.4 格式化函数

VS2015之博大精深的MFC项目开发(一)_第75张图片

printf函数的打印目标是控制台,sprintf函数的打印目标是字符串(缓冲区),也就是说给printf加上s的话,参数里就必须再加一个字符串的地址(缓冲区),打印的目标要送到这个缓冲区里面:
VS2015之博大精深的MFC项目开发(一)_第76张图片

VS2015之博大精深的MFC项目开发(一)_第77张图片

在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第78张图片

VS2015之博大精深的MFC项目开发(一)_第79张图片


4、MFC02-2:Windows消息处理机制

VS2015之博大精深的MFC项目开发(一)_第80张图片


4.1 windows消息列表

VS2015之博大精深的MFC项目开发(一)_第81张图片

VS2015之博大精深的MFC项目开发(一)_第82张图片

VS2015之博大精深的MFC项目开发(一)_第83张图片

在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第84张图片


4.2 测试其他的消息种类

插入一个对话框,测试一下对话框里都有哪些消息可用:
VS2015之博大精深的MFC项目开发(一)_第85张图片

VS2015之博大精深的MFC项目开发(一)_第86张图片

VS2015之博大精深的MFC项目开发(一)_第87张图片

VS2015之博大精深的MFC项目开发(一)_第88张图片

VS2015之博大精深的MFC项目开发(一)_第89张图片

VS2015之博大精深的MFC项目开发(一)_第90张图片

VS2015之博大精深的MFC项目开发(一)_第91张图片

VS2015之博大精深的MFC项目开发(一)_第92张图片

我们如何把鼠标左键按下的位置显示在对话框窗口上呢?
VS2015之博大精深的MFC项目开发(一)_第93张图片

VS2015之博大精深的MFC项目开发(一)_第94张图片

VS2015之博大精深的MFC项目开发(一)_第95张图片

一般在case区域你要定义变量,编译是会不通过的,所以要给这个case区域加个大括号,在这个区域内使用变量x和y,这是C语言case语句的语法要求。

VS2015之博大精深的MFC项目开发(一)_第96张图片

VS2015之博大精深的MFC项目开发(一)_第97张图片

VS2015之博大精深的MFC项目开发(一)_第98张图片

将变量的类型改为short就可以显示负数了:
VS2015之博大精深的MFC项目开发(一)_第99张图片

VS2015之博大精深的MFC项目开发(一)_第100张图片

VS2015之博大精深的MFC项目开发(一)_第101张图片

VS2015之博大精深的MFC项目开发(一)_第102张图片


5、MFC02-3:Windows类型介绍

VS2015之博大精深的MFC项目开发(一)_第103张图片

VS2015之博大精深的MFC项目开发(一)_第104张图片

VS2015之博大精深的MFC项目开发(一)_第105张图片

VS2015之博大精深的MFC项目开发(一)_第106张图片

not captured,就是当鼠标移出了对话框窗口客户区之外的时候,标题栏上的文字就不响应了(不响应鼠标移动消息了),离开窗口的话光标就无效了,光标在窗口内的话就响应鼠标移动消息,也就是说包含光标的窗口才能收到这个消息;
the window that has captured the mouse,也就是把这个光标绑到这个窗口,离开窗口之后光标仍然有效。

VS2015之博大精深的MFC项目开发(一)_第107张图片

继续研究wParam参数,如何把按下左键拖动也能显示出来呢?
VS2015之博大精深的MFC项目开发(一)_第108张图片

VS2015之博大精深的MFC项目开发(一)_第109张图片

VS2015之博大精深的MFC项目开发(一)_第110张图片

按下左键拖动的同时按下ctrl键:
VS2015之博大精深的MFC项目开发(一)_第111张图片


5.1 windows的变量类型

VS2015之博大精深的MFC项目开发(一)_第112张图片

VS2015之博大精深的MFC项目开发(一)_第113张图片

VS2015之博大精深的MFC项目开发(一)_第114张图片

VS2015之博大精深的MFC项目开发(一)_第115张图片

VS2015之博大精深的MFC项目开发(一)_第116张图片

VS2015之博大精深的MFC项目开发(一)_第117张图片

VS2015之博大精深的MFC项目开发(一)_第118张图片

VS2015之博大精深的MFC项目开发(一)_第119张图片


解析DECLARE_HANDLE宏

VS2015之博大精深的MFC项目开发(一)_第120张图片

我们可以看到,任何一个句柄都是一个结构体指针变量,指向一个不让你知道的内存空间,比方说一个窗口的句柄,它可能指向的内存空间里实际上有20多个变量,包括窗口的位置,窗口的类型等等,可能有很多种数据,但是它不让你知道,这是一种故意不让你看到真实内容的结构体,隐藏了它实际的内容。

类似于我们在C语言当中学的FILE*指针类型:
VS2015之博大精深的MFC项目开发(一)_第121张图片

每一种句柄都是被隐藏了实际内容的一种指针变量,都是4个字节。

VS2015之博大精深的MFC项目开发(一)_第122张图片


5.2 简介MFC开发

今后我们在做MFC开发的时候,这个InitInstance虚函数可以当做是WinMain函数,真正的WinMain函数被它隐藏起来了。
VS2015之博大精深的MFC项目开发(一)_第123张图片

上图这是向导给我们生成的MFC程序,我们把InitInstance函数中自动生成的其余代码如上图所示删除掉,这里主要是要弹出一个对话框。

VS2015之博大精深的MFC项目开发(一)_第124张图片

该函数在弹出对话框的时候呢,它是把这个对话框的ID放到一个对话框类里:
VS2015之博大精深的MFC项目开发(一)_第125张图片

只要定义了这个类的对象,你在需要弹出对话框的时候,因为这个对象包含了这个对话框的ID,系统就会帮你加载这个对话框,定义了这个对话框对象之后,可以调用它所继承的基类的成员函数,就可以弹出对话框、设置背景颜色、关闭对话框:
VS2015之博大精深的MFC项目开发(一)_第126张图片

VS2015之博大精深的MFC项目开发(一)_第127张图片

VS2015之博大精深的MFC项目开发(一)_第128张图片

VS2015之博大精深的MFC项目开发(一)_第129张图片


用MFC开发四则运算计算器程序

VS2015之博大精深的MFC项目开发(一)_第130张图片

VS2015之博大精深的MFC项目开发(一)_第131张图片

VS2015之博大精深的MFC项目开发(一)_第132张图片

VS2015之博大精深的MFC项目开发(一)_第133张图片

拖拽复制这些控件:

VS2015之博大精深的MFC项目开发(一)_第134张图片

VS2015之博大精深的MFC项目开发(一)_第135张图片

在左侧标尺那里你可以打一条线,让这一行上的控件对齐。

VS2015之博大精深的MFC项目开发(一)_第136张图片

双击一个按钮就会自动生成这个按钮对应的操作函数:
VS2015之博大精深的MFC项目开发(一)_第137张图片

这种函数叫做消息映射函数。

VS2015之博大精深的MFC项目开发(一)_第138张图片

BEGIN_MESSAGE_MAP宏做了一个消息映射,把一个ID关联到一个成员函数上,而且是点击动作的消息类型。

在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第139张图片

我们可以从上面看到,它最终还是把命令消息关联到该命令对应的函数。

VS2015之博大精深的MFC项目开发(一)_第140张图片

这种消息映射机制,我们就叫做:一消息、一ID、一函数;
有的时候也有不带ID的,即一消息、一函数。

我们这里为了简单演示,先只做int类型的计算。

VS2015之博大精深的MFC项目开发(一)_第141张图片

VS2015之博大精深的MFC项目开发(一)_第142张图片

我们看到CDialog类是由CWnd类派生下来的,所有的窗口、控件都属于CWnd类。

VS2015之博大精深的MFC项目开发(一)_第143张图片

VS2015之博大精深的MFC项目开发(一)_第144张图片

VS2015之博大精深的MFC项目开发(一)_第145张图片

我们可以看到,在API中有4个参数,它必须要带入句柄,而我们这里写的程序为什么只有3个参数,不用带入句柄呢?
VS2015之博大精深的MFC项目开发(一)_第146张图片

下断点,按F11进去看一下:
VS2015之博大精深的MFC项目开发(一)_第147张图片

我们可以看到它仍然要调用系统API并带入句柄,只不过这个句柄m_hWnd已经缺省被保存在成员变量里了,也就是CWnd类的核心成员变量只有一个,就是这个句柄HWND:
VS2015之博大精深的MFC项目开发(一)_第148张图片

既然你的对话框已经弹出来了,它把句柄已经给你保存好了,所以你每次都不用写句柄了,这个句柄都被窗口类CWnd管理好了,你就不用管句柄了,每次调用函数的时候省去了句柄的带入。

在这里插入图片描述

在这里插入图片描述

这些C++成员函数经常给有些参数常用的缺省值,从代码编写上就省了很多参数的填写。


6、MFC03-1:Win32程序界面权限登录开发

VS2015之博大精深的MFC项目开发(一)_第149张图片


6.1 实现对话框启动后居中显示

VS2015之博大精深的MFC项目开发(一)_第150张图片

为了实现让对话框启动后居中显示,还要获取你显示器的高度和宽度(屏幕分辨率):
VS2015之博大精深的MFC项目开发(一)_第151张图片

VS2015之博大精深的MFC项目开发(一)_第152张图片

梳理一下代码,将IDOK分支里的计算封装成函数OnCalc:
VS2015之博大精深的MFC项目开发(一)_第153张图片

VS2015之博大精深的MFC项目开发(一)_第154张图片

VS2015之博大精深的MFC项目开发(一)_第155张图片

VS2015之博大精深的MFC项目开发(一)_第156张图片

VS2015之博大精深的MFC项目开发(一)_第157张图片

VS2015之博大精深的MFC项目开发(一)_第158张图片

VS2015之博大精深的MFC项目开发(一)_第159张图片

在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第160张图片

VS2015之博大精深的MFC项目开发(一)_第161张图片

我们可以看到全屏和屏幕的高度有所不同,全屏的不包含系统任务栏,用全屏的尺寸(以桌面客户区为主)更美观。

VS2015之博大精深的MFC项目开发(一)_第162张图片

半个屏幕宽度减去半个窗口宽度,就得出了实现窗口居中所需要的x坐标;
半个屏幕高度减去半个窗口高度,就得出了实现窗口居中所需要的y坐标。

VS2015之博大精深的MFC项目开发(一)_第163张图片

VS2015之博大精深的MFC项目开发(一)_第164张图片

VS2015之博大精深的MFC项目开发(一)_第165张图片

在这个移动的过程中,如果这个窗口是已经显示出来了,移动的时候你最好加TRUE,让它自动刷新就可以了,边移动的时候要刷一刷窗口的显示,让移动窗口显得更平滑自然;
而我们这里是在OnInitDialog函数中,窗口还没显示出来之前,那你就不用重新刷新了,因为本来就没显示,这里该参数用FALSE就可以。


6.2 实现登录界面

添加一个对话框资源:
VS2015之博大精深的MFC项目开发(一)_第166张图片

给按钮居中排列:
VS2015之博大精深的MFC项目开发(一)_第167张图片

VS2015之博大精深的MFC项目开发(一)_第168张图片

VS2015之博大精深的MFC项目开发(一)_第169张图片

现在我们这个程序是Win32的,并不是MFC,我们先来用Win32实现;
登录有自己登录的处理函数,主窗口有主窗口的处理函数,Win32的开发模式就是每一个窗口你都要给它一个消息处理函数:
VS2015之博大精深的MFC项目开发(一)_第170张图片

VS2015之博大精深的MFC项目开发(一)_第171张图片

VS2015之博大精深的MFC项目开发(一)_第172张图片

VS2015之博大精深的MFC项目开发(一)_第173张图片

VS2015之博大精深的MFC项目开发(一)_第174张图片

当你点击登录界面的退出按钮时,就不进入主界面,当你点击登录按钮时,主界面就出来了,但是此时我们没有对用户名、密码进行判断。


7、MFC03-2:MFC架构与原理分析1

7.1 完成登录对话框居中显示,用户名密码匹配

VS2015之博大精深的MFC项目开发(一)_第175张图片

接着,我们要根据输入的用户名和密码是否正确来决定是否要执行EndDialog:
VS2015之博大精深的MFC项目开发(一)_第176张图片

VS2015之博大精深的MFC项目开发(一)_第177张图片


7.2 编辑控件的属性

VS2015之博大精深的MFC项目开发(一)_第178张图片

VS2015之博大精深的MFC项目开发(一)_第179张图片

VS2015之博大精深的MFC项目开发(一)_第180张图片

如果要加一个记事本功能的编辑框的话,记得把自动横向滚动(Auto HScroll)和自动纵向滚动(Auto VScroll)改为FALSE,Multiline和Want Return改为True,以及很重要的Vertical Scroll改为True:
VS2015之博大精深的MFC项目开发(一)_第181张图片

VS2015之博大精深的MFC项目开发(一)_第182张图片

VS2015之博大精深的MFC项目开发(一)_第183张图片

我们添加一个只读属性的编辑框,用来显示用户名、密码输入错误的提示:
VS2015之博大精深的MFC项目开发(一)_第184张图片

VS2015之博大精深的MFC项目开发(一)_第185张图片

VS2015之博大精深的MFC项目开发(一)_第186张图片

上图的SetDlgItemText函数的位置放在OnInitDialog函数的前面试试。

VS2015之博大精深的MFC项目开发(一)_第187张图片


7.3 测试各种windows消息

VS2015之博大精深的MFC项目开发(一)_第188张图片

VS2015之博大精深的MFC项目开发(一)_第189张图片

VS2015之博大精深的MFC项目开发(一)_第190张图片

VS2015之博大精深的MFC项目开发(一)_第191张图片

我们发现在处理WM_SETCURSOR消息的时候,可以把只读编辑框里面的提示信息显示出来。

VS2015之博大精深的MFC项目开发(一)_第192张图片

它的意思是说,我的鼠标在什么控件上移动,我就有不同的提示;这个消息叫鼠标光标切换消息。

在这里插入图片描述

我们测试一下该消息的lParam的高2字节是否是控件的ID:
VS2015之博大精深的MFC项目开发(一)_第193张图片

测试效果不明显,我们再试试wParam是否包含控件的句柄:
VS2015之博大精深的MFC项目开发(一)_第194张图片

VS2015之博大精深的MFC项目开发(一)_第195张图片

这个测试效果明显,鼠标在不同的控件中移动的时候,wParam中就包含了对应控件的句柄。

7.4 用MFC开发计算器

能不能把已经以前工程中编辑好的对话框加入到新的工程里面去呢?
也就是说,把前面用Win32写的计算器对话框里面的控件拖到新工程中的对话框上呢?

新建一个MFC工程,把该MFC工程自动生成的对话框上面的控件全部删除,点击文件、打开、文件:
VS2015之博大精深的MFC项目开发(一)_第196张图片

VS2015之博大精深的MFC项目开发(一)_第197张图片

打开前面已经写好的Win32工程中的.rc文件:
VS2015之博大精深的MFC项目开发(一)_第198张图片

VS2015之博大精深的MFC项目开发(一)_第199张图片

ctrl+a全选,ctrl+c复制,再打开mfc工程中的对话框,粘贴上去:
VS2015之博大精深的MFC项目开发(一)_第200张图片

把粘贴不过来的图片先删除掉。

VS2015之博大精深的MFC项目开发(一)_第201张图片

我们对上图OnOK函数那行设置一个断点,看看它做了什么:
在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第202张图片

如果你想要点击计算后不关闭对话框,把该行注释掉或者直接删除就可以了,这个时候你回车的话就不会关闭对话框了。

VS2015之博大精深的MFC项目开发(一)_第203张图片

VS2015之博大精深的MFC项目开发(一)_第204张图片

VS2015之博大精深的MFC项目开发(一)_第205张图片

VS2015之博大精深的MFC项目开发(一)_第206张图片

VS2015之博大精深的MFC项目开发(一)_第207张图片

VS2015之博大精深的MFC项目开发(一)_第208张图片

上图这是一个公用头文件区。

VS2015之博大精深的MFC项目开发(一)_第209张图片

VS2015之博大精深的MFC项目开发(一)_第210张图片

VS2015之博大精深的MFC项目开发(一)_第211张图片


8、MFC03-3:MFC架构与原理分析2

VS2015之博大精深的MFC项目开发(一)_第212张图片

我们可以看到MFC框架中是有WinMain函数的,只不过给你隐藏起来了。

VS2015之博大精深的MFC项目开发(一)_第213张图片

在这里插入图片描述

InitInstance是个虚函数,回调到你这个用户代码这里:
VS2015之博大精深的MFC项目开发(一)_第214张图片

你可以就把自己程序当中的InitInstance当做主函数,当做WinMain函数,不用去关心真正的WinMain函数在干什么,你只要知道程序启动的时候就在这里进行调用就可以了;
可以把向导自动生成的无用的代码都删除掉:
VS2015之博大精深的MFC项目开发(一)_第215张图片

VS2015之博大精深的MFC项目开发(一)_第216张图片

VS2015之博大精深的MFC项目开发(一)_第217张图片

从上面两张图片可以看到生成的这两个类所包含的成员函数。

一个对话框类会跟一个对话框的模板资源,形成关联。

VS2015之博大精深的MFC项目开发(一)_第218张图片

对话框类在构造函数的时候,把一个对话框模板送到它的基类,它的基类在DoModal的时候就拿这个模板去加载对话框;
另外它还加载了一个图标IDR_MAINFRAME,把这个图标在设置到对话框上面去:
VS2015之博大精深的MFC项目开发(一)_第219张图片

VS2015之博大精深的MFC项目开发(一)_第220张图片

如果你把这两行SetIcon函数都注释掉,就不显示左上角这个好看的图标了:
在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第221张图片

这是一个没什么用的函数,微软一直没有把它删除掉。

VS2015之博大精深的MFC项目开发(一)_第222张图片

VS2015之博大精深的MFC项目开发(一)_第223张图片

VS2015之博大精深的MFC项目开发(一)_第224张图片

把计算器程序中的输入编辑框改为右对齐,输出结果的编辑框改为只读:
VS2015之博大精深的MFC项目开发(一)_第225张图片


8.1 把原始的Win32程序改造为MFC程序

先建立一个普通的Win32项目:
VS2015之博大精深的MFC项目开发(一)_第226张图片
VS2015之博大精深的MFC项目开发(一)_第227张图片

VS2015之博大精深的MFC项目开发(一)_第228张图片

VS2015之博大精深的MFC项目开发(一)_第229张图片

VS2015之博大精深的MFC项目开发(一)_第230张图片

VS2015之博大精深的MFC项目开发(一)_第231张图片

VS2015之博大精深的MFC项目开发(一)_第232张图片

VS2015之博大精深的MFC项目开发(一)_第233张图片

VS2015之博大精深的MFC项目开发(一)_第234张图片

VS2015之博大精深的MFC项目开发(一)_第235张图片

此时,我们在对话框上放上计算加法的几个控件,并双击这个对话框确定按钮,发现没有自动生成响应函数,而是弹出一个MFC添加类向导对话框:
VS2015之博大精深的MFC项目开发(一)_第236张图片

就是说,你光用一个基类CDialogEx去定义一个对象,它是无法处理你这里面的消息的,也就是说你无法在这个基类中去编写代码,你必须把这个基类再派生一次,也就是我们经常在开发MFC的时候看到的两个类,一个是App类,一个是Dialog类:
VS2015之博大精深的MFC项目开发(一)_第237张图片

你把这个对话框,根据这个IDD_MAIN_DLG,做一个CDialogEx的派生类CMainDlg,这样的话就生成了App类与Dialog类联用的这种标准的MFC程序。
这样我们就把MFC的开发原理就搞清楚了。
这个派生类是用来做消息映射,一个消息对一个成员函数,你不可能把这个消息映射做到基类里面去,因为基类是在系统里,你不可能跑到系统里去编写代码,你肯定要自己做个派生类,在自己的类里去编写代码。

VS2015之博大精深的MFC项目开发(一)_第238张图片

也可以直接右击对话框窗体,点击添加类,你双击一个按钮也会走到这一步:
VS2015之博大精深的MFC项目开发(一)_第239张图片

VS2015之博大精深的MFC项目开发(一)_第240张图片

VS2015之博大精深的MFC项目开发(一)_第241张图片

我们双击对话框上的任何一个按钮,就可以建立一个关联的成员函数,这里我们生成一个这个按钮的回调函数:
VS2015之博大精深的MFC项目开发(一)_第242张图片

要记得在MainDlg.h开头添加resource.h头文件才能识别IDD_MAIN_DLG:
VS2015之博大精深的MFC项目开发(一)_第243张图片

我们在OnBnClickedOk函数中下个断点,编译运行程序,现在肯定能弹出我们这个自定义的对话框:
VS2015之博大精深的MFC项目开发(一)_第244张图片

但是点击确定按钮后,这个对话框直接关闭了,而没有进入到我们的消息映射函数,这是为什么呢?
VS2015之博大精深的MFC项目开发(一)_第245张图片

原因就是说我们这里用的是基类构建的这个对话框类的对象(如上图所示),它有消息的话都会送到基类去,所以这里要改为派生类来建立对象:
VS2015之博大精深的MFC项目开发(一)_第246张图片

在这个派生类创建对象的时候不需要传参了,因为在这个派生类构造函数中它会自动往基类中传参的,它会自动往基类送IDD_MAIN_DLG,所以你这里就不用传参了:
VS2015之博大精深的MFC项目开发(一)_第247张图片

这次再点击确定按钮,就映射到派生类的这个消息处理函数里来了。

VS2015之博大精深的MFC项目开发(一)_第248张图片

VS2015之博大精深的MFC项目开发(一)_第249张图片

VS2015之博大精深的MFC项目开发(一)_第250张图片

那么,那些LBUTTONDOWN、SETFOCUS这些消息都是怎么创建的呢?
VS2015之博大精深的MFC项目开发(一)_第251张图片

在MFC中把这个窗口的所有消息都给你列了出来:
VS2015之博大精深的MFC项目开发(一)_第252张图片

VS2015之博大精深的MFC项目开发(一)_第253张图片

你都可以通过类向导去截获这些消息来利用这些消息,处理这些消息。

消息映射函数有两种,一种就是直接由消息映射成函数,另一种消息还要配合ID生成函数,就是一消息加一个ID生成一个函数:
VS2015之博大精深的MFC项目开发(一)_第254张图片

因为有很多个按钮,它必须配合ID才能确定你点击的是哪个按钮,而LBUTTONDOWN就不存在这个问题,我只要点击一下就行了,我不可能有5个光标点击,我只有一个光标点击,所以是一消息生成一个函数。

VS2015之博大精深的MFC项目开发(一)_第255张图片

VS2015之博大精深的MFC项目开发(一)_第256张图片

有很多地方都可以打开这个类向导:
VS2015之博大精深的MFC项目开发(一)_第257张图片

再给MouseMove消息做一个响应函数:
VS2015之博大精深的MFC项目开发(一)_第258张图片

VS2015之博大精深的MFC项目开发(一)_第259张图片

我们MFC把一个拆分好的坐标放在一个MFC对象CPoint里面:
VS2015之博大精深的MFC项目开发(一)_第260张图片

VS2015之博大精深的MFC项目开发(一)_第261张图片

VS2015之博大精深的MFC项目开发(一)_第262张图片

VS2015之博大精深的MFC项目开发(一)_第263张图片

VS2015之博大精深的MFC项目开发(一)_第264张图片

该消息处理函数的第一个参数nFlags其实就是Win32程序中回调函数中的wParam参数:
VS2015之博大精深的MFC项目开发(一)_第265张图片

VS2015之博大精深的MFC项目开发(一)_第266张图片

VS2015之博大精深的MFC项目开发(一)_第267张图片

VS2015之博大精深的MFC项目开发(一)_第268张图片

留个作业,用MFC实现前面用Win32做的登录对话框那个程序,也就是再添加一个对话框作为登录对话框:
VS2015之博大精深的MFC项目开发(一)_第269张图片

9、MFC04-1:用MFC应用程序向导建立MFC工程

VS2015之博大精深的MFC项目开发(一)_第270张图片

VS2015之博大精深的MFC项目开发(一)_第271张图片

VS2015之博大精深的MFC项目开发(一)_第272张图片

VS2015之博大精深的MFC项目开发(一)_第273张图片

VS2015之博大精深的MFC项目开发(一)_第274张图片

VS2015之博大精深的MFC项目开发(一)_第275张图片

VS2015之博大精深的MFC项目开发(一)_第276张图片

VS2015之博大精深的MFC项目开发(一)_第277张图片

上图左下角的带小箭头的东西叫做全局对象的声明,或者是成员变量的声明,双击带箭头的小图标,你会发现在App的.h头文件有这个全局变量的声明,定义只能有一份(在App的.cpp文件中),但是这种声明可以有多份,这只是一个引导性的语句,它不是一个真正的变量,让看不见这个变量的地方可以使用这个变量;
有了这个全局变量的声明,使用起来更加方便,不然的话你只能在这个全局变量定义所在的.cpp文件中使用,你出了这个文件那你如何能看到这个全局变量呢,那主要就是通过全局变量的声明:
VS2015之博大精深的MFC项目开发(一)_第278张图片

当然你也可以把这个全局变量的声明放在stdafx.h这个公有区的头文件中:
VS2015之博大精深的MFC项目开发(一)_第279张图片

凡是你在这个头文件放上的东西几乎在所有的.cpp中可见,因为这是一个公有的头文件。

VS2015之博大精深的MFC项目开发(一)_第280张图片

编译报错,是因为该公有头文件对CCalcApp这个类不可见,所以加上该类的头文件Calc.h:
VS2015之博大精深的MFC项目开发(一)_第281张图片

我们说过我们可以把InitInstance当做WinMain主函数来使用:
VS2015之博大精深的MFC项目开发(一)_第282张图片

把向导给我们自动生成的InitInstance函数多余的代码删除掉。

VS2015之博大精深的MFC项目开发(一)_第283张图片

我们发现,为什么在消息映射表里没有这个OnInitDialog呢?
原因就是我们有3个缺省的系统消息,被系统接管了的消息:
WM_INITDIALOG、WM_COMMAND下的IDOK和IDCANCEL消息。

VS2015之博大精深的MFC项目开发(一)_第284张图片

VS2015之博大精深的MFC项目开发(一)_第285张图片

VS2015之博大精深的MFC项目开发(一)_第286张图片

我们把这3个消息叫做系统接管了的对话框消息。
我们看到在消息列表里没有这3个消息,但是它们为什么能够被调用呢?
在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第287张图片

我们点击IDOK按钮断下再看看:
VS2015之博大精深的MFC项目开发(一)_第288张图片

它也是一个COMMAND消息。
这是3个被系统缺省管理的消息,实际上在我们这里的MFC开发有两种回调函数,一种是虚函数回调,一种是消息映射回调。

OK按钮、CANCEL取消按钮以及初始化InitDialog,这三个是缺省的系统消息,它们被系统缺省管理了的系统消息;
并且在基类中把这3个函数做成虚函数回调。

VS2015之博大精深的MFC项目开发(一)_第289张图片

比如上图的InitInstance、OnInitDialog,以及OK、Cancel被做成了虚函数回调;
我们去基类当中看看这这几个函数:
VS2015之博大精深的MFC项目开发(一)_第290张图片

VS2015之博大精深的MFC项目开发(一)_第291张图片

VS2015之博大精深的MFC项目开发(一)_第292张图片

我们可以看到在基类中系统有这几个函数的缺省处理,系统接管了之后就会缺省执行关闭:
VS2015之博大精深的MFC项目开发(一)_第293张图片

所以,我们只要一建立了这个工程,你一点击这个取消按钮或者是OK按钮,它们就会自动关闭,这就是因为系统有对这两个按钮的缺省处理。

VS2015之博大精深的MFC项目开发(一)_第294张图片

我们现在知道,CCalcDlg这是一个用来接收关于IDD_CALC_DIALOG对话框消息的派生类,有了这个类,用这个类的对象来DoModal你才能够接收到这个对话框内的所有事件返回的消息;
你点击、鼠标移动,那些消息都会反馈到这个类CCalcDlg里面来接收消息。

我们前面做过的添加以前工程中做好的对话框资源,是通过文件、打开、文件的方式把.rc资源文件打开,再把对话框上的控件全选复制到新工程资源上的,我们直接拖动.rc文件中的资源,是拖不进现有工程资源中的:
VS2015之博大精深的MFC项目开发(一)_第295张图片

为了把以前工程中做好的对话框资源、位图资源添加进我们新的工程中,我们用另外一种方法添加:
VS2015之博大精深的MFC项目开发(一)_第296张图片

把.rc资源文件添加进来后,我们现有工程中就有两个资源文件了:
VS2015之博大精深的MFC项目开发(一)_第297张图片

VS2015之博大精深的MFC项目开发(一)_第298张图片

现在就可以把以前工程TestDlg.rc中的IDD_MAIN_DLG对话框资源拖进我们当前Calc.rc资源中来了,以及IDB_TEST位图资源、IDR_MENU1资源都可以拖过来了:
VS2015之博大精深的MFC项目开发(一)_第299张图片

拖完了之后就可以把刚才添加进来的以前的资源文件删掉了,不保存别人的东西:
VS2015之博大精深的MFC项目开发(一)_第300张图片

VS2015之博大精深的MFC项目开发(一)_第301张图片

什么东西都被拖进来了,这样的方式就使得我们开发对话框就容易了。

我们把以前向导给我们生成的对话框模板IDD_CALC_DIALOG给删掉,把向基类CDialogEx传参的对话框模板的ID修改为我们保留的IDD_MAIN_DLG:
VS2015之博大精深的MFC项目开发(一)_第302张图片

VS2015之博大精深的MFC项目开发(一)_第303张图片

这个时候编译运行,就会把这个对话框弹出来了。

VS2015之博大精深的MFC项目开发(一)_第304张图片

如果你把这个CCalcDlg::OnCancel()这个函数整个给删掉和留在这里,效果是一样的,你把这个函数删掉,系统会自动接管这个由基类接管的函数;你不删掉摆在这里,在该函数中再去调用基类的这个OnCancel函数,效果是一样的;
如果你在这里去掉CDialog::OnCancel()这一句话,这个对话框就关闭不掉了。

我们给这个对话框把菜单加进来:
VS2015之博大精深的MFC项目开发(一)_第305张图片

然后把这个对话框属性里的Menu这一项改为该Menu的ID,主界面就有菜单可用了:
在这里插入图片描述

我们之前的Win32程序,不但有主对话框,而且还有登录对话框,我们看见别人有什么,我们就想拿别人的东西过来,把前面的Win32程序中的登录对话框添加进来:
VS2015之博大精深的MFC项目开发(一)_第306张图片

VS2015之博大精深的MFC项目开发(一)_第307张图片

看见什么就往我们工程里面拖,这样的话你在做这个项目的时候就快了;
然后再把这个TestDlg.rc按Del键给不保存删掉,不要破坏掉别人的资源。

VS2015之博大精深的MFC项目开发(一)_第308张图片

我们现在有两个对话框可以使用了,但是我们却只有一个主对话框的类CCalcDlg可以用:
VS2015之博大精深的MFC项目开发(一)_第309张图片

我们可以看到,在启动程序这里只有一个主对话框在DoModal,却没有第二个对话框在DoModal,那么我们这个登录对话框怎么能够出现,怎么能够影响到主对话框的弹出呢?
VS2015之博大精深的MFC项目开发(一)_第310张图片

这里要给这个登录对话框添加一个关联类:
VS2015之博大精深的MFC项目开发(一)_第311张图片

VS2015之博大精深的MFC项目开发(一)_第312张图片


9.1 简介MFC六大关键技术

App这个类就是MFC的启动技术:
VS2015之博大精深的MFC项目开发(一)_第313张图片

启动技术就是说它没有WinMain函数给你,它把WinMain函数接管到系统内部,在运行的过程中通过一个InitInstance这个虚函数回调回来,这个函数就可以认为是MFC的第一大关键技术,它是启动管理技术。

第二大关键技术,就是我们天天能看到的消息映射机制,一个是DECLARE_MESSAGE_MAP,一个是BEGIN_MESSAGE_MAP。
VS2015之博大精深的MFC项目开发(一)_第314张图片

VS2015之博大精深的MFC项目开发(一)_第315张图片

第三大关键技术,以后我们会介绍,就是刚才的对话框类这里看到的动态创建技术,即DECLARE_DYNAMIC:
VS2015之博大精深的MFC项目开发(一)_第316张图片

现在我们怎么把这个新生成的类弹出来呢?
我们让Login对话框先弹出,主对话框后弹出:
VS2015之博大精深的MFC项目开发(一)_第317张图片

VS2015之博大精深的MFC项目开发(一)_第318张图片

VS2015之博大精深的MFC项目开发(一)_第319张图片

VS2015之博大精深的MFC项目开发(一)_第320张图片

由于登录对话框上的用户名编辑框我们设置的属性为只支持大写字母,所以需要把大写字母转换为小写字母再进行比较。

VS2015之博大精深的MFC项目开发(一)_第321张图片

在这里插入图片描述

这里的函数只对英文字母有影响,对于符号、数字以及中文字符都没有影响。

VS2015之博大精深的MFC项目开发(一)_第322张图片

关于这个CString类的成员函数,大家都应该测试一下,这里还有很多拆解函数都非常好用,都非常有用:
VS2015之博大精深的MFC项目开发(一)_第323张图片

VS2015之博大精深的MFC项目开发(一)_第324张图片

在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第325张图片

VS2015之博大精深的MFC项目开发(一)_第326张图片

VS2015之博大精深的MFC项目开发(一)_第327张图片

VS2015之博大精深的MFC项目开发(一)_第328张图片

另外还有一种不区分大小写的比较函数:
VS2015之博大精深的MFC项目开发(一)_第329张图片

Compare函数我们一般不用,用CString重载过的==或!=运算符更方便。

VS2015之博大精深的MFC项目开发(一)_第330张图片

VS2015之博大精深的MFC项目开发(一)_第331张图片


9.2 UNICODE编码简介

VS2015之博大精深的MFC项目开发(一)_第332张图片

注意一下,上图MultiByteToWideChar后面的中文解释说反了,WideCharToMultiByte后面的也说反了。

VS2015之博大精深的MFC项目开发(一)_第333张图片

各国语言的编码都各自独立,就是统一编码Unicode。

10、MFC04-2:UNICODE编码的应用

我们建立一个简单的Win32的空项目,来测试一下UNICODE编码的使用。
在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第334张图片

VS2015之博大精深的MFC项目开发(一)_第335张图片

VS2015之博大精深的MFC项目开发(一)_第336张图片

我们现在来测试一下Unicode文字和非Unicode文件它们的区别是什么?
VS2015之博大精深的MFC项目开发(一)_第337张图片

VS2015之博大精深的MFC项目开发(一)_第338张图片

VS2015之博大精深的MFC项目开发(一)_第339张图片

VS2015之博大精深的MFC项目开发(一)_第340张图片

在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第341张图片

VS2015之博大精深的MFC项目开发(一)_第342张图片

VS2015之博大精深的MFC项目开发(一)_第343张图片

上面的两张图中的const wchar_t [4]和const wchar_t [3],这个4和3应该是字符个数,也就是多了一个看不见的结尾0字符。

VS2015之博大精深的MFC项目开发(一)_第344张图片


10.1 TCHAR

当你把工程切换为多字符集的时候,你就得把每个字符串前面大写的L给去掉,很麻烦:
VS2015之博大精深的MFC项目开发(一)_第345张图片

VS2015之博大精深的MFC项目开发(一)_第346张图片

而当你又切换成Unicode环境的时候,你又得把每个文字前面带上大写字母L,非常麻烦。

VS2015之博大精深的MFC项目开发(一)_第347张图片

VS2015之博大精深的MFC项目开发(一)_第348张图片

VS2015之博大精深的MFC项目开发(一)_第349张图片

目前项目的字符集是Unicode字符集:
VS2015之博大精深的MFC项目开发(一)_第350张图片

VS2015之博大精深的MFC项目开发(一)_第351张图片

L是将字符串常量转换为Unicode,那么有没有一种东西能够让常量自动转化的?
在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第352张图片

VS2015之博大精深的MFC项目开发(一)_第353张图片

VS2015之博大精深的MFC项目开发(一)_第354张图片

为了让代码具有可移植性,在Unicode和非Unicode都能使用的话,每个字符串前面都要添加_T或者_Text,
VS2015之博大精深的MFC项目开发(一)_第355张图片

MFC的函数也是这样的,字符串参数类型也是TCHAR*的类型,它就具有了可移植性,两种字符集平台都可以使用:
VS2015之博大精深的MFC项目开发(一)_第356张图片

VS2015之博大精深的MFC项目开发(一)_第357张图片


10.2 Unicode与多字符集字符串互相转换

VS2015之博大精深的MFC项目开发(一)_第358张图片


10.3 MultiByteToWideChar函数

VS2015之博大精深的MFC项目开发(一)_第359张图片

VS2015之博大精深的MFC项目开发(一)_第360张图片

上图这个-1代表,这个字符串一直跑到结尾就可以了,你不用指定字节数了,有多少转换多少,有多长转换多长。

VS2015之博大精深的MFC项目开发(一)_第361张图片

我们有更简单的用一个参数就能搞定转换的函数,下节课会讲。


11、MFC04-3:Unicode与多字符集字符串互相转换

VS2015之博大精深的MFC项目开发(一)_第362张图片

VS2015之博大精深的MFC项目开发(一)_第363张图片

注意一下,上图MultiByteToWideChar后面的中文解释说反了,WideCharToMultiByte后面的也说反了。


11.1 WideCharToMultiByte函数

VS2015之博大精深的MFC项目开发(一)_第364张图片

VS2015之博大精深的MFC项目开发(一)_第365张图片

这种转换都是很笨的转换,还有更加简单的Unicode转换的方法:
VS2015之博大精深的MFC项目开发(一)_第366张图片

VS2015之博大精深的MFC项目开发(一)_第367张图片

VS2015之博大精深的MFC项目开发(一)_第368张图片

VS2015之博大精深的MFC项目开发(一)_第369张图片

VS2015之博大精深的MFC项目开发(一)_第370张图片

VS2015之博大精深的MFC项目开发(一)_第371张图片

我们不熟悉W2A的参数,可以先F12看看声明:
VS2015之博大精深的MFC项目开发(一)_第372张图片

VS2015之博大精深的MFC项目开发(一)_第373张图片

VS2015之博大精深的MFC项目开发(一)_第374张图片

VS2015之博大精深的MFC项目开发(一)_第375张图片

这几种函数平时用的比较少。

VS2015之博大精深的MFC项目开发(一)_第376张图片

我们平时用的比较多的是_bstr_t类,这个类也是开发COM常用的;这个类里面没有什么函数,它里面也是模仿CString来做的,只不过它里面能够放两种指针,一条是宽的,一条是窄的,因此你既可以把p1带进来,也可以把s1带进来,它可以接纳两种字符串:
VS2015之博大精深的MFC项目开发(一)_第377张图片

_bstr_t类在这里编译链接会报链接错误,因为我们现在这个项目是一个Win32项目,_bstr_t类适合MFC工程,在大型的MFC工程中用这个类就比较方便;
最好不在Win32下使用,因为它要链接一些MFC的库,这个类宽的我也能接受,窄的我也能接受:
VS2015之博大精深的MFC项目开发(一)_第378张图片
在这里插入图片描述

CString里面用的是TCHAR,CString它自身是有自适应的,它只能在某个字符集环境下单一的接受,_bstr_t就比较牛了,两种字符集它都能接受,它里面放点Unicode,还能再放点非Unicode,最后能统一生成一种char*格式:
VS2015之博大精深的MFC项目开发(一)_第379张图片

Unicode和非Unicode合并在一起,然后会生成一个非Unicode的指针:
VS2015之博大精深的MFC项目开发(一)_第380张图片

我们通过内存窗口可以观察到,这是一个窄类型的字符串,我还可以再从这个_bstr_t类的对象中取宽字符,这个类是两种字符串都能放进去,两种字符串都能取出来:
VS2015之博大精深的MFC项目开发(一)_第381张图片

这个都是堆区上的东西,它里面存放了两个堆,即存放了Unicode的堆区,也存放了非Unicode的堆区,你既可以把Unicode的东西存进去,也可以把非Unicode的东西放进去;
所以_bstr_t是我们在开发中最喜欢使用的字符串转换方式,两种字符集的转换它都能做得到。


11.2 在窗口上实时显示当前时间

VS2015之博大精深的MFC项目开发(一)_第382张图片

VS2015之博大精深的MFC项目开发(一)_第383张图片

这个类最核心的算法是,把你的年月日时分秒合并成一个64位的变量 __time64_t 存进去。

VS2015之博大精深的MFC项目开发(一)_第384张图片

VS2015之博大精深的MFC项目开发(一)_第385张图片

VS2015之博大精深的MFC项目开发(一)_第386张图片

我们来把当前时间实时的显示在登录对话框的只读的提示框里:
VS2015之博大精深的MFC项目开发(一)_第387张图片

我们从上图左下角可以看到,这个登录对话框类里还没有OnInitDialog初始化消息,我们可以直接用类向导:
VS2015之博大精深的MFC项目开发(一)_第388张图片

VS2015之博大精深的MFC项目开发(一)_第389张图片

我们发现在消息里并没有找到WM_INITDIALOG消息,这个本来是一个消息的,只不过被系统接管过去了,变成了虚函数让我们再回调回来。

VS2015之博大精深的MFC项目开发(一)_第390张图片

VS2015之博大精深的MFC项目开发(一)_第391张图片

VS2015之博大精深的MFC项目开发(一)_第392张图片

VS2015之博大精深的MFC项目开发(一)_第393张图片

在这里插入图片描述

如果你想让这个时间不停的更新的话,就要用定时器消息。

VS2015之博大精深的MFC项目开发(一)_第394张图片

VS2015之博大精深的MFC项目开发(一)_第395张图片

VS2015之博大精深的MFC项目开发(一)_第396张图片

VS2015之博大精深的MFC项目开发(一)_第397张图片

VS2015之博大精深的MFC项目开发(一)_第398张图片

VS2015之博大精深的MFC项目开发(一)_第399张图片

它是在调用窗口类CWND的SetTimer函数时,指定了每间隔多少时间来产生这个WM_TIMER消息,这个消息将定时的发生。

VS2015之博大精深的MFC项目开发(一)_第400张图片

在这里插入图片描述

这个函数就是设置、安装定时器,你没安装的话它就不刷新;该函数的第一个参数就是定时器的编号,比如说1号定时器的时间间隔是1秒,2号定时器的时间间隔是500毫秒,而这些不同定时器的编号会在OnTimer的第一个参数nIDEvent中进行分类识别(你可以用switch给它们区分开进行处理)。

VS2015之博大精深的MFC项目开发(一)_第401张图片

这个消息就会每隔1秒钟来一次。


11.3 封装一个自己的CRect类

VS2015之博大精深的MFC项目开发(一)_第402张图片

新建一个MFC项目来模拟封装Win32下的RECT结构体为一个类:
VS2015之博大精深的MFC项目开发(一)_第403张图片

VS2015之博大精深的MFC项目开发(一)_第404张图片

我们要实现的功能是,只要你的鼠标一靠近这个同意按钮,这个同意按钮就会跑,不让你点击它。

VS2015之博大精深的MFC项目开发(一)_第405张图片

VS2015之博大精深的MFC项目开发(一)_第406张图片

这个WM_SETCURSOR是鼠标在各个控件之间切换的时候,产生的一个消息;也就是鼠标光标在各个控件上面移动的时候产生的。

VS2015之博大精深的MFC项目开发(一)_第407张图片

VS2015之博大精深的MFC项目开发(一)_第408张图片

VS2015之博大精深的MFC项目开发(一)_第409张图片

ID为0是对话框窗口,ID为2是取消按钮的ID,即IDCancel。

VS2015之博大精深的MFC项目开发(一)_第410张图片

这个同意按钮的ID就是1000,我们可以从Resource.h中看到这个按钮的ID就是1000:
VS2015之博大精深的MFC项目开发(一)_第411张图片

这就证明了只要你鼠标一移到哪个按钮(控件)上,它就有这个WM_SETCURSOR消息的发生。

VS2015之博大精深的MFC项目开发(一)_第412张图片

在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第413张图片

VS2015之博大精深的MFC项目开发(一)_第414张图片

刚要点同意按钮,结果就变成移动这个对话框了,默认的MoveWindow(&rect)只指this->MoveWindow(&rect),这个this指针就是指我们这个对话框,我们现在是this移动,也就是对话框移动了;
当进来的窗口句柄的ID是IDC_TEST的时候,我们就知道了pWnd就是这个同意按钮的句柄(指针):
VS2015之博大精深的MFC项目开发(一)_第415张图片

VS2015之博大精深的MFC项目开发(一)_第416张图片

我们再次测试发现按钮跑到右下方来了,跑的太远了,我们不是说让它跑到右边一格么,这是怎么回事呢?


11.4 屏幕坐标系和窗口坐标系

我们把整个屏幕截图放到画图程序里进行分析:

VS2015之博大精深的MFC项目开发(一)_第417张图片

我们分析可以得知,上图这个244、212其实是以屏幕左上角为坐标系原点0,0来说的,如下图画笔坐在位置即为整个屏幕的244,212坐标点:
VS2015之博大精深的MFC项目开发(一)_第418张图片

这个同意按钮以屏幕坐标系来看是在这个244,212这个坐标点上的,我们本来是想要把它移动到这个坐标点右边这个按钮宽度的位置,为什么它却移动到右下方来了呢?
因为MoveWindow在移动窗口的时候,它是以TestRect对话框左上角为坐标系原点0,0,移动到332,237位置的话就跑到这个对话框窗口的右下方了,我们在画图程序中把这个截图往左上角移动,让TestRect对话框左上角作为原点,即如下图所示:
VS2015之博大精深的MFC项目开发(一)_第419张图片

从上图左下角的坐标334,301可以看到,这个同意按钮移动的位置就是以TestRect对话框窗口左上角为坐标系原点的。
这就是由于坐标系不同导致的问题:
VS2015之博大精深的MFC项目开发(一)_第420张图片

对于GetWindowRect来说,是以屏幕左上角为原点的坐标系。

VS2015之博大精深的MFC项目开发(一)_第421张图片

对于MoveWindow来说对于子窗口(子CWnd对象),x和y是相对于父窗口工作区的左上角作为坐标系原点来说的。

在这里插入图片描述

所以这里需要有一个坐标的切换,把传进去的屏幕坐标系的rect(该参数为输入输出型参数)变为以这个this指向的对话框客户区为新原点的坐标系。

VS2015之博大精深的MFC项目开发(一)_第422张图片

这就获取了一个屏幕的坐标系,转换为客户区坐标系:
VS2015之博大精深的MFC项目开发(一)_第423张图片

在画图中可以看到,以这个对话框左上角为坐标系原点,这个同意按钮的左上角坐标就是12,12位置,说明确实将屏幕坐标系转换为了窗口客户区坐标系了:
VS2015之博大精深的MFC项目开发(一)_第424张图片

VS2015之博大精深的MFC项目开发(一)_第425张图片

VS2015之博大精深的MFC项目开发(一)_第426张图片

这时候再去移动就是以客户区为单位的了,就是让你永远都点不到同意按钮。

我们修改下程序,再取得一个rect,如果按钮跑到客户区界线了就让它恢复回来:
VS2015之博大精深的MFC项目开发(一)_第427张图片

VS2015之博大精深的MFC项目开发(一)_第428张图片

小窗口(同意按钮)的右边已经跑到大窗口(客户区)的外面了,就让它回到左边去。

如果我们采用MFC的CRect代替Rect的话,这个CRect的到处是什么呢,我们来看一看:
VS2015之博大精深的MFC项目开发(一)_第429张图片

好处就是不用取地址了,直接带入这个CRect对象就可以了,这是因为CRect类里面有类型转换成员函数:
VS2015之博大精深的MFC项目开发(一)_第430张图片

就是说一个对象所属的类有运算符重载了之后,你即可以把它当作对象,又可以把它当作对象的地址,等价于你取了对象的地址,对象自己会把自己的地址取出来,不用你再去写取地址符号了。

VS2015之博大精深的MFC项目开发(一)_第431张图片

VS2015之博大精深的MFC项目开发(一)_第432张图片

VS2015之博大精深的MFC项目开发(一)_第433张图片

VS2015之博大精深的MFC项目开发(一)_第434张图片

还能进行压缩,向中间压缩,向四周扩张:
在这里插入图片描述

还能够平移:
VS2015之博大精深的MFC项目开发(一)_第435张图片

VS2015之博大精深的MFC项目开发(一)_第436张图片


12、MFC05-1:MFC的六大关键技术

VS2015之博大精深的MFC项目开发(一)_第437张图片


12.1 MFC的六大关键技术都有哪些

  • MFC程序的初始化过程
  • 运行时类型识别(RTTI)
  • 动态创建
  • 永久保存
  • 消息映射
  • 消息传递

VS2015之博大精深的MFC项目开发(一)_第438张图片

VS2015之博大精深的MFC项目开发(一)_第439张图片

VS2015之博大精深的MFC项目开发(一)_第440张图片


12.2 浅谈消息映射机制

MFC把每个对话框对应到一个类:
VS2015之博大精深的MFC项目开发(一)_第441张图片
VS2015之博大精深的MFC项目开发(一)_第442张图片

每个对话框都有一个对应的类,一个对话框资源配一个类,这样的话每一个对话框的消息会在对应的类中去接收,这样程序架构的组成就比较干净利落一些。

VS2015之博大精深的MFC项目开发(一)_第443张图片

我们只要把类向导打开,在上面双击一个消息,就产生一个消息映射函数;
这就是消息映射机制对于我们程序开发带来的好处。

VS2015之博大精深的MFC项目开发(一)_第444张图片

VS2015之博大精深的MFC项目开发(一)_第445张图片

VS2015之博大精深的MFC项目开发(一)_第446张图片


12.3 再谈屏幕坐标系和窗口坐标系

VS2015之博大精深的MFC项目开发(一)_第447张图片

它参考的坐标是以屏幕的左上角为原点。

VS2015之博大精深的MFC项目开发(一)_第448张图片

在这里插入图片描述
这就是窗口客户区坐标系,GetClientRect每次取出来的左上角都是0,0,它主要能取出来右下角的坐标560,350,我们按照这样一个矩形区域画一个椭圆。

VS2015之博大精深的MFC项目开发(一)_第449张图片

VS2015之博大精深的MFC项目开发(一)_第450张图片

VS2015之博大精深的MFC项目开发(一)_第451张图片

VS2015之博大精深的MFC项目开发(一)_第452张图片

VS2015之博大精深的MFC项目开发(一)_第453张图片

VS2015之博大精深的MFC项目开发(一)_第454张图片

VS2015之博大精深的MFC项目开发(一)_第455张图片

VS2015之博大精深的MFC项目开发(一)_第456张图片

VS2015之博大精深的MFC项目开发(一)_第457张图片

VS2015之博大精深的MFC项目开发(一)_第458张图片

VS2015之博大精深的MFC项目开发(一)_第459张图片

VS2015之博大精深的MFC项目开发(一)_第460张图片

VS2015之博大精深的MFC项目开发(一)_第461张图片

13、MFC05-2:MFC基础变量类型

13.1 模仿开发CPoint类

鼠标右击类视图添加一个类:
VS2015之博大精深的MFC项目开发(一)_第462张图片

VS2015之博大精深的MFC项目开发(一)_第463张图片

VS2015之博大精深的MFC项目开发(一)_第464张图片

这些基础类型在外面MFC工程下是必然会存在的,我们在MFC下有一个公用的头文件叫stdafx.h,这个头文件就把所有的公用的头文件都包含起来了。
VS2015之博大精深的MFC项目开发(一)_第465张图片

其中我们最主要的头文件就是afxwin.h,凡是afx开头的都是MFC头文件,在Win32开发下的时候是没有任何一个头文件是afx开头的。
VS2015之博大精深的MFC项目开发(一)_第466张图片
凡是windows.h有的东西,afxwin.h这个头文件里面都有。

VS2015之博大精深的MFC项目开发(一)_第467张图片

VS2015之博大精深的MFC项目开发(一)_第468张图片

VS2015之博大精深的MFC项目开发(一)_第469张图片

我们再做一个Offset成员函数:
VS2015之博大精深的MFC项目开发(一)_第470张图片

在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第471张图片

测试这个自定义的类:
VS2015之博大精深的MFC项目开发(一)_第472张图片

VS2015之博大精深的MFC项目开发(一)_第473张图片

VS2015之博大精深的MFC项目开发(一)_第474张图片

VS2015之博大精深的MFC项目开发(一)_第475张图片


13.2 封装CRect类

VS2015之博大精深的MFC项目开发(一)_第476张图片

VS2015之博大精深的MFC项目开发(一)_第477张图片

VS2015之博大精深的MFC项目开发(一)_第478张图片
在这里插入图片描述

我们给这个自定义的类创建一个类型转换函数,将自己的对象变换成其他的类型:
VS2015之博大精深的MFC项目开发(一)_第479张图片

VS2015之博大精深的MFC项目开发(一)_第480张图片

VS2015之博大精深的MFC项目开发(一)_第481张图片

VS2015之博大精深的MFC项目开发(一)_第482张图片

VS2015之博大精深的MFC项目开发(一)_第483张图片

我们可以参考微软的CRect的TopLeft函数,看看微软是怎么做的:
VS2015之博大精深的MFC项目开发(一)_第484张图片

VS2015之博大精深的MFC项目开发(一)_第485张图片

VS2015之博大精深的MFC项目开发(一)_第486张图片

VS2015之博大精深的MFC项目开发(一)_第487张图片

因为这里的TopLeft返回的是一个引用,所以如果我们把返回的pt.x和pt.y修改后,请问rect会不会发生改变呀?
如果是引用的话,它等价于是一个指针变量,指向到这个rect上面,所以rect会发生改变,如下图所示:
在这里插入图片描述

这就是加引用和不加引用的区别。

VS2015之博大精深的MFC项目开发(一)_第488张图片

我们还看到pt和地址和rect的地址一样,而pb的地址其实刚好指向了rect的腰,是rect的下8个字节,指向的是rect的右下角的right和bottom这两个成员变量。

如果我们去掉引用的话,这个时候的改变就不会影响到rect本身:
VS2015之博大精深的MFC项目开发(一)_第489张图片

可以看到pt和pb这两个CPoint的地址,和rect的地址没有重叠。

如果我们的CRectLx类里面没有定义只读的TopLeft成员函数的话,如下这种只读的对象参数是无法调用普通成员函数的:
VS2015之博大精深的MFC项目开发(一)_第490张图片

只读对象只能调用只读成员函数。

在这里插入图片描述

在这里插入图片描述

如果你把Width成员函数的只读性给去掉的话,它怀疑你会改变rect里面的成员变量;
只读成员函数是可以给只读对象使用的。

VS2015之博大精深的MFC项目开发(一)_第491张图片

你定义一个临时对象并对这个临时对象进行修改这是可以的;
但是this指向的对象内部自己的数据是不可以修改的:

在这里插入图片描述

VS2015之博大精深的MFC项目开发(一)_第492张图片

这就是上图这两个只读成员函数产生的原因,就是因为它要返回一个只读性质的CPoint,返回的值也不能修改这里面的数据;
不但它不能调用普通的成员函数,连它的返回值都不能修改。

在这里插入图片描述

用一个普通的CPoint来接收只读对象调用的只读函数(这个函数返回只读的引用类型的CPoint)是可以的;

你把pt改为引用的话就报错了,它不让你去挂只读的对象:
VS2015之博大精深的MFC项目开发(一)_第493张图片

如果你要挂必须用只读的去挂:
在这里插入图片描述

只读函数将用于只读对象。


14、MFC05-3:简单MFC程序设计

14.1 继续模拟CRect类的常用成员函数

函数CenterPoint的实现

VS2015之博大精深的MFC项目开发(一)_第494张图片
接着我们来看只读函数CenterPoint的实现,凡是这种只读函数都是给那种只读对象来使用的,不然的话只读对象就怕你在不加const的函数里面修改只读对象的成员变量,凡是const函数是禁止修改它的每一个成员变量的。

在这里插入图片描述

在这里插入图片描述


函数IsRectEmpty和IsRectNull的实现

VS2015之博大精深的MFC项目开发(一)_第495张图片

接着我们来看看IsRectEmpty和IsRectNull这两个函数是什么意思,有什么区别?
VS2015之博大精深的MFC项目开发(一)_第496张图片

我们来创建一个没有面积的CRect对象(因为这个矩形的宽度为0):
VS2015之博大精深的MFC项目开发(一)_第497张图片

VS2015之博大精深的MFC项目开发(一)_第498张图片

从上图可以知道,Empty只是面积为空,那么Null的话就不止面积为空了:
VS2015之博大精深的MFC项目开发(一)_第499张图片

比方说我们创建一个左上角坐标(0,0)和右下角坐标(0,20)的矩形:
VS2015之博大精深的MFC项目开发(一)_第500张图片

我们编译运行发现还是Empty,少一个0这个IsRectNull都不成立。

VS2015之博大精深的MFC项目开发(一)_第501张图片

VS2015之博大精深的MFC项目开发(一)_第502张图片

果然4个0的话IsRectNull就成立了。

VS2015之博大精深的MFC项目开发(一)_第503张图片

VS2015之博大精深的MFC项目开发(一)_第504张图片


函数InflateRect和函数DeflateRect的实现

VS2015之博大精深的MFC项目开发(一)_第505张图片

Inflate的意思是说向四周膨胀。
VS2015之博大精深的MFC项目开发(一)_第506张图片

deflate就是向中间压缩。
VS2015之博大精深的MFC项目开发(一)_第507张图片

VS2015之博大精深的MFC项目开发(一)_第508张图片

VS2015之博大精深的MFC项目开发(一)_第509张图片

对于两个矩形是否相等的判断,我们可以用一个memcmp函数去进行判断,把整个矩形区域的4个变量全部比较一遍,也就是把内存空间比较一遍。

VS2015之博大精深的MFC项目开发(一)_第510张图片


演示一下NormalizeRect函数的功能

我们先创建一个有问题的矩形(左边大于右边,上边大于下边):
VS2015之博大精深的MFC项目开发(一)_第511张图片

我们可以看到它的宽度是-28,高度是-58,执行了NormalizeRect之后呢,把左上角和右下角的坐标值对调了一下:
VS2015之博大精深的MFC项目开发(一)_第512张图片

把有问题的矩形变成正常化了;
你自己实现的时候完全可以用一个if语句判断一下,如果left大于right的话给它俩对调,如果top大于bottom的话给它俩对调。

对于MFC类库中的每一个函数,你都要非常清晰的知道这个函数的用法。


14.2 继续完善计算器程序

VS2015之博大精深的MFC项目开发(一)_第513张图片

VS2015之博大精深的MFC项目开发(一)_第514张图片

VS2015之博大精深的MFC项目开发(一)_第515张图片

你用TCHAR的话,字符串常量也要用可移植性的才行:
VS2015之博大精深的MFC项目开发(一)_第516张图片

p[0]的赋值不好,也应该用_T去“修饰”字符:
VS2015之博大精深的MFC项目开发(一)_第517张图片

VS2015之博大精深的MFC项目开发(一)_第518张图片

VS2015之博大精深的MFC项目开发(一)_第519张图片

在这里插入图片描述

原因就是因为atof这个函数是一个窄函数,由于当前平台是Unicode字符集,所以要调用宽函数:
VS2015之博大精深的MFC项目开发(一)_第520张图片

VS2015之博大精深的MFC项目开发(一)_第521张图片

所以在遇到C语言函数的时候一定要看看微软有没有对这些窄字节函数做出宽字节版本的函数。

VS2015之博大精深的MFC项目开发(一)_第522张图片

推荐使用_tstof或_ttof这种自适应的、可移植的函数。

VS2015之博大精深的MFC项目开发(一)_第523张图片

VS2015之博大精深的MFC项目开发(一)_第524张图片

当我们按F11跟进去的时候,它必然会有一个operator类型转换函数:
在这里插入图片描述

当你去用到它的指针的时候,编译器就会自动返回PCXSTR类型的指针,能够把字符串的地址取出来。

在这里插入图片描述

编译的错误就是因为必须在双引号前面加上_T才可以。

VS2015之博大精深的MFC项目开发(一)_第525张图片

VS2015之博大精深的MFC项目开发(一)_第526张图片

VS2015之博大精深的MFC项目开发(一)_第527张图片

凡是遇到上面这种错误的时候,我们最好点重试按钮,我们虽然出错了,但是我们也有机会演示当弹出这个对话框,我们应该做什么,之后你再去看调用栈,找到自己写的函数。

VS2015之博大精深的MFC项目开发(一)_第528张图片

VS2015之博大精深的MFC项目开发(一)_第529张图片

VS2015之博大精深的MFC项目开发(一)_第530张图片
VS2015之博大精深的MFC项目开发(一)_第531张图片

大家见到这种弹出的框,你要会用重试按钮,点中止的话就错了,你要会善于利用这个弹出的错误,一定要点它的重试按钮,点了重试按钮之后,再要去看调用栈,你会找到发生错误的那一行,可以快速定位你的错误。

你可能感兴趣的:(windows程序设计,vs2015的MFC项目开发)