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

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

  • 第二章 MFC原理篇
    • 1、MFC06-1:CString类的测试
      • 1.1 operator+函数
      • 1.2 Delete函数
      • 1.3 Find函数
      • 1.4 Insert函数
      • 1.5 切分函数(Mid、Left、Right)
      • 1.6 其它函数
      • 1.7 反向查找函数ReverseFind
    • 2、MFC06-2:开发一个带列表控件的软件
      • 2.1 Trim系列函数
      • 2.2 GetBuffer和ReleaseBuffer函数
      • 2.3 开发一个带列表控件的软件(CListCtrl类)
    • 3、MFC06-2:继续完善带列表控件的软件开发
      • 3.1 设置界面背景和文字背景颜色
      • 3.2 设置列表扩展风格
      • 3.3 单选某行和多选一些行的特性
    • 4、MFC07-1:完善员工信息管理功能项目开发
      • 4.1 设置焦点
      • 4.2 实现保存功能
    • 5、MFC07-2:继续完善员工信息管理项目开发
      • 5.1 实现加载功能
      • 5.2 把日期类型转换为字符串
      • 5.3 实现修改功能(单行)
      • 5.4 实现多行修改
      • 5.5 实现删除
      • 5.6 实现退出功能
    • 6、MFC07-3:MFC类库封装原理
      • 6.1 在C语言中我们是如何使用时间的
      • 6.2 使用MFC类库中的时间族CTime
      • 6.3 用C语言把你的生日存入到一个时间对象里
      • 6.4 再看看MFC类的存入时间的方法
      • 6.5 自己封装一个Time类
    • 7、MFC08-1:开发一个记事本软件
      • 7.1 讲解初始化消息OnInitDialog
      • 7.2 添加菜单资源
      • 7.3 实现菜单退出项的功能
      • 7.4 记事本的文件拖入打开功能
        • 对拖入的每个文件名进行提取
    • 8、MFC08-2:继续开发记事本软件
      • 8.1 对话框窗体的属性(外观、行为)
      • 8.2 编辑控件的风格
      • 8.3 完善编辑框的功能
      • 8.4 添加一下close消息处理
    • 9、MFC08-3:记事本软件功能完善
      • 9.1 粘贴功能
      • 9.2 实现粘贴功能
      • 9.3 全选功能
      • 9.4 插入日期
      • 9.5 简介消息映射
      • 9.6 剖析消息映射机制
        • DECLARE_MESSAGE_MAP、BEGIN_MESSAGE_MAP
    • 10、MFC09-1:读取文本文件的软件开发
      • 10.1 文本编码格式(UTF-8、UTF-16)
      • 10.2 读取UTF-8转换为Unicode
    • 11、MFC09-2:对话框常用的回调函数
      • 11.1 读取Unicode文件
      • 11.2 对话框常用的回调函数
        • 11.2.1 WM_CREATE和WM_INITDIALOG消息
        • 11.2.2 WM_CLOSE和WM_DESTROY消息
        • 11.2.3 测试WM_SYSCOMMAND消息
        • 11.2.4 测试WM_CLOSE消息
        • 11.2.5 OnCancel虚函数
        • 11.2.6 WM_DESTROY消息
    • 12、MFC09-3:消息传递函数
      • 12.1 SendMessage函数
      • 12.2 PostMessage函数
      • 12.3 Win32下测试SendMessage的返回值
      • 12.4 MFC下测试SendMessage的返回值
        • 在MFC中自定义消息应该怎么建立呢?


第二章 MFC原理篇

1、MFC06-1:CString类的测试

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

在这里插入图片描述


1.1 operator+函数

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

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

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

那么两个TCHAR是否能相加呢?

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

错了,不能想加,我们学C语言的时候都知道,两个指针相减还是有道理的,两个指针相减是两个地址之间的距离,是一个整数;
但是两个指针相加那就没有道理了。
只有第一个是对象,或者第二个是对象,才可以无限的连加,后面再有多少个字符串就都没问题了。

在这里插入图片描述


1.2 Delete函数

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

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

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

我们在试试给参数nCount设为-1看看能不能删除到结尾:

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

在这里插入图片描述

我们看到参数2设为-1没有效果。

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

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

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

我故意把参数2的值也得很长,程序也不会崩溃。


1.3 Find函数

在这里插入图片描述

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

我们发现没查找到,这是因为我们查找的那串字符不是个字符串。

在这里插入图片描述

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

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

如果这个Find函数查不到的话就返回-1。

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

从第5个位置开始查找的话,字符a在整个字符串的第6个位置上。

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

大家在每要测试一个新的内容的时候,要新建一个按钮专门测试这个内容。

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


1.4 Insert函数

在这里插入图片描述

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

每测一个函数你要用心的把它用心的做一个按钮,好好的练一下。

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

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

在字符串中间某个位置插入的话:

在这里插入图片描述

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


1.5 切分函数(Mid、Left、Right)

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

在这里插入图片描述

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

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

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

Mid函数是一个功能全面的切分函数,用Mid可以代替Left和Right函数,当你要字符串左边3个或者字符串右边3个的话,用Left和Right比较方便。

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

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

如果要求从字符串第3个位置以后的部分,有几种方法可以实现呢?

  • 用Right函数来实现

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

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

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

  • 用Mid函数来实现

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

在这里插入图片描述

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

第2个参数如果为-1的话不行,返回值为空。

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

我们发现第2个参数设置为字符串长度也可以,该值超长的话也不出错。

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

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

其实按照函数说明,不提供第2个参数的话,会一直到结尾;
单参数版本的Mid函数就是指从第几个位置开始一直到结尾。

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

所以说,Mid是功能最全面的切分函数,凡是Right能做到的,Left能做到的,Mid都能做到。

要切字符串右边的3个:

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

或者用单参数版本也行:

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

Mid函数也可以实现Left的功能:

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

在我们模拟CString类的时候,Left和Right的功能我们可以用Mid这个函数做出来。


1.6 其它函数

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

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

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

这个nID参数是指资源中字符串表中的字符串,如果资源中没有字符串表,你可以加入一个;
字符串表中可以放一些测试的字符串:

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

IDS_TEST这个ID将生成到resource.h当中,因为它是一个资源的ID:

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

我们看到这是一个整数,那么这个整数我们在什么时候使用呢?
当你需要使用字符串列表中的文字的时候:

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

现在很少使用LoadString函数了,它主要是以前做多国语言版的时候用的,现在有Unicode的话就没必要做多国语言版了。

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

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

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

在这里插入图片描述

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

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

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


1.7 反向查找函数ReverseFind

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

这个反向查找不支持查找一个字符串,只支持查找一个字符。

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

比方说当我们获得一个目录的时候,我们要从中找到当前的执行文件名:

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

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

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

就得到了程序运行目录,这个是非常好用的,因为在我们程序运行目录下往往还会有一些图片,我们要加载与程序相同目录下的资源、一些文件的时候,这种方法还是非常好用的。

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

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

在这里插入图片描述

在windows下一般用\r\n更能准确的代表换行,在linux下一般直接就用\n代表换行。

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


2、MFC06-2:开发一个带列表控件的软件

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

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

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

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

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

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


2.1 Trim系列函数

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

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

不带参数的Trim只裁剪字符串两端的空格,中间的空格不裁剪。

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

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

中间如果有空格、括号等包含在要裁剪的字符集中的字符仍然不裁,Trim只裁剪左右两端的。

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

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


2.2 GetBuffer和ReleaseBuffer函数

这是两个CString类中非常有用的函数,也是最古怪的CString对象的成员函数。

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

我们经常有一些API的参数是C语言格式的字符串(LPSTR或者LPTSTR),我们想把它直接获取到CString对象里面去(API本来就不支持对象),这样的话以前我们比较笨的方法就是首先定义一个字符缓冲区:
VS2015之博大精深的MFC项目开发(二)_第74张图片

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

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

现在可以直接通过CString对象来获取缓冲区:
VS2015之博大精深的MFC项目开发(二)_第77张图片

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

它会在内部的堆空间上去分配1000个,沿着这1000个去获取,获取完了之后必须要执行ReleaseBuffer函数,它是一个修复函数,必须要用ReleaseBuffer对这个str进行修复,因为在调用GetBuffer之前我们这个str的长度是空的,GetBuffer之后这个str的长度可能还是0,但是你经过ReleaseBuffer对这个str字符串进行修复之后,str将成为真正有用的字符串了,GetLength将会是实际获取到的那个字符串的长度:
VS2015之博大精深的MFC项目开发(二)_第79张图片

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

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

我们从上图可以看到,即使是str获取到了系统目录字符串,但是它的长度仍然为0,所以我们要用ReleaseBuffer这个函数对它进行修复一下,修复了之后这个字符串才成为真正可用的字符串:
VS2015之博大精深的MFC项目开发(二)_第82张图片


2.3 开发一个带列表控件的软件(CListCtrl类)

在这里插入图片描述

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

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

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

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

把按回车键默认关闭的代码注释掉,但是按ESC的话可以关闭,所以删除确定按钮,保留取消按钮。

ListBox是一个简易的列表,只有单行效果,现在一般都不用了;
现在凡是多行列表的都是ListControl:
VS2015之博大精深的MFC项目开发(二)_第87张图片

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

上图这个Edit Labels可以让你实现,点击一个文件名,再点击一下就可以编辑这个文件名:
在这里插入图片描述

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

每一种控件都有自己对应的类,因为不同的控件有不同的操作。

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

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

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

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

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

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

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

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

运行起来出错了,一定要记得点重试按钮,再点中断:
VS2015之博大精深的MFC项目开发(二)_第98张图片

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

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

双击打开你自己的程序代码,错误应该就是在刚编写的InsertColumn这一行上,没插进去,而且崩溃了。

我们首先看一下CListCtrl这个类的基类是什么:
VS2015之博大精深的MFC项目开发(二)_第101张图片

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

而CWnd类核心的成员变量就是一个窗口句柄:
VS2015之博大精深的MFC项目开发(二)_第103张图片

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

我们看到这个句柄是空的;
你创建了一个CListCtrl对象,你要拿这个对象去操作什么,比如说有5个ListControl控件,谁知道你要操作哪一个ListControl控件,你必须将这个CListCtrl对象和某一个控件的ID关联到一起,它没有关联到任何控件上,是不可以操作任何控件的,所以上面这样写是错的。

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

我们要看CWnd类的该成员函数,因为CWnd类是我们MFC的窗口类。

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

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

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

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

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

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

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

接着我们点击添加按钮的时候插入行:
在这里插入图片描述

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

消息映射表中就是:一消息(WM_COMMAND)、一ID、一函数。

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

GetDlgItem函数的返回值说明中,上图所选这句话,是说该函数的返回值是一个临时性指针变量,不要把它储存到成员变量里长期使用;
就是说你每个消息处理函数中都通过GetDlgItem函数获取一下,因为它是一个临时性的,会随时被清理掉。

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

在这里插入图片描述

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

这个InsertItem函数是插入一行,它只能添加该行第一列的内容,后面列的内容就不支持添加了。

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

item就是指最左边的列这一项叫item,subitem就是右边剩余的项。

在这里插入图片描述

它不但可以设置最左边这一列的文字,也可以通过nSubItem设置其他列的文字。

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

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

我们看到最后的日期没有放进来。


3、MFC06-2:继续完善带列表控件的软件开发

通过上节课的学习,我们知道了CListCtrl类的InsertColumn是插入列,InsertItem是插入行,SetItemText可以设置每一行上每列的文字。

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

把SetItemText函数第2个参数设为0就是给该行第0列添加文字。

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

我们再插入一列用来添加入职日期:
VS2015之博大精深的MFC项目开发(二)_第122张图片

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

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

我们把列宽再调整一下:
VS2015之博大精深的MFC项目开发(二)_第125张图片

现在我们把日期中的星期一这3个字符给它切掉:
VS2015之博大精深的MFC项目开发(二)_第126张图片

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


3.1 设置界面背景和文字背景颜色

我们还能让列表美化一下:
VS2015之博大精深的MFC项目开发(二)_第128张图片

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

我们可以通过画图程序得到想要的颜色值,比如下图中所选中这一行的颜色:
在这里插入图片描述

按PrtSc SysRq键全屏拷贝,粘贴到画图板程序上,然后我们用提取工具吸一下截图上选中行的颜色:
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张图片

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


3.2 设置列表扩展风格

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

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

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

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

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

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

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

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

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

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

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

留个作业:
VS2015之博大精深的MFC项目开发(二)_第151张图片

插入的时候,如果要插入的工号已存在就禁止插入,提示已存在!


3.3 单选某行和多选一些行的特性

我们删除功能要完成的是,选中某一行,点击删除按钮删除:
VS2015之博大精深的MFC项目开发(二)_第152张图片

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

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

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

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

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

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

GetSelectionMark这个函数是获得第一个选中行的位置,如上图所示这个虚框,是一个单选标志,在你鼠标第一次点击的位置上,永远不可能有两个同时被选中的这种虚框,只要这个虚框在它就认为被选中了;
虚线总是在一行上,不可能在多行上。

GetSelectedCount函数是多选标志,就是有多少个实际被打上蓝色的:
VS2015之博大精深的MFC项目开发(二)_第159张图片

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

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

你仔细看上图可以看到这个虚线(虚框)还在,现在你要删除的话,GetSelectionMask函数有效,但是GetSelectedCount函数无效,它认为一个都没选中,但是这种情况下GetSelectionMask仍然是有效的。

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

这样的情况下,即使你一行没选中,它有个虚线(虚框)在那里,GetSelectionMask也认为是选中了:
VS2015之博大精深的MFC项目开发(二)_第163张图片

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

而GetSelectedCount它是多行选择,它是按照蓝色作为选中标志的。

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

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

这个函数很显然是多选函数,它可以把第一个被选中的位置返回;它常和GetNextSelectedItem函数配合使用可以遍历选中的多项:
VS2015之博大精深的MFC项目开发(二)_第167张图片

你在程序里也可以用多选的这类函数,因为多选毕竟更准确一些,多选是以蓝色为选中标志,更醒目。

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

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

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

留个作业:
用多选标志之类的函数实现上述删除功能。

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

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

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

你如果不想让它多选,可以设置Single Selection属性为True。

在这里插入图片描述

这个属性是非常重要的属性,就是当你焦点离开了这个列表,它还一直是选中的状态。
如下图所示,当你焦点离开,它还有一个灰色的选中标志:

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

现在我们怎么能够不倒着插入每一行呢?
我们想到的笨的不实用的方法就是定义一个全局变量或者成员变量,每插入一行就i++,如果中间有删除的话i也相应自减,但是这种方法比较麻烦,这个i你要自己维护。
VS2015之博大精深的MFC项目开发(二)_第175张图片

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

如果这个列表控件自身就带有记录总数的功能就比较好了,也就是说我们不需要定义一个全局变量或者成员变量来维护;
CListCtrl类中有GetItemCount函数能够获取到总数:
在这里插入图片描述

在这里插入图片描述

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

这样的话我们就可以正序插入了,不再倒序插入了。

留个作业:
写个循环,判断所插入的工号是否已经存在,禁止重复录入。

我们希望把列表中的数据保存到一个文件中,待下次打开软件时,可以通过加载按钮加载进软件列表里。
VS2015之博大精深的MFC项目开发(二)_第178张图片

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

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

编译运行测试后发现可以创建文件。

我们以后再实现循环的把列表中每一行的数据保存在文件里,并且还能从文件中加载数据到列表中。


4、MFC07-1:完善员工信息管理功能项目开发

我们要做一个循环查找要添加的工号是否已有记录。
VS2015之博大精深的MFC项目开发(二)_第181张图片

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

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

当点击上图确定后,我们想让焦点在已经清空的工号编辑框里,以便重新输入;
由于添加按钮函数里的代码太多了,所以我们给CWorkerDlg添加一个成员函数:
VS2015之博大精深的MFC项目开发(二)_第184张图片

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

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


4.1 设置焦点

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

给对话框设置焦点,我们测试程序发现焦点并没有设置成功。

我们按ctrl+d看一下tab顺序:
VS2015之博大精深的MFC项目开发(二)_第188张图片

我们用鼠标点击这些编号就能改变顺序:
VS2015之博大精深的MFC项目开发(二)_第189张图片

让程序启动的时候焦点就落在1号上,由于1是不接受焦点的,所以焦点会自动落在2上。
我们可以查看这两个控件的Tabstop属性:
VS2015之博大精深的MFC项目开发(二)_第190张图片

在这里插入图片描述

设置变量i的值为当前总行数就可以实现在当前行的下一行上插入:
VS2015之博大精深的MFC项目开发(二)_第191张图片

把CheckNumber的参数改为LPCTSTR类型:
VS2015之博大精深的MFC项目开发(二)_第192张图片

修改头文件中该函数的声明:
VS2015之博大精深的MFC项目开发(二)_第193张图片

我们如果想实现删除选中的多行数据(不连续、间隔的,例如用按着ctrl键用鼠标点击第3、5、7行):
VS2015之博大精深的MFC项目开发(二)_第194张图片

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

选中项我们要全部删除,怎么样来循环把选中的几项都删掉呢?
这里我们先完成修改函数,因为修改会把选中的几项全部修改成一样的。


4.2 实现保存功能

对了,先等等,我们还是先把保存函数先做好,这样方便其他功能的测试:
VS2015之博大精深的MFC项目开发(二)_第196张图片

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

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

这个SInfo结构体是私有的,自己用的,不需要对外边使用,那你就放在类内就可以了。

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

在退出的时候我们要遍历每一个列表项,把数据存下去。

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

为什么sName这个成员不使用可以自动增长CString类型呢?用CString的话就不用管它的长度,用多少就使多少,但是需要很复杂的计算,为什么呢?
因为CString里面是一个指针变量,它在结构体中只占4个字节,你把CString里面的指针变量存到文件里了,那么进程退出后,这个指针变量指向的内存肯定是释放了,重新启动这个进程,把文件中该指针的值提取出来,这个指针所指向的位置上根本没有你上次保存的名字那些数据;
所以说,CString不能直接存在文件里,也不能发送给网络程序把这个CString给另一台机器,你要把这个CString实际指向的内容发送出去才对。

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

要计算数组大小要用sizeof,也就是整个结构体在控件上占用的字节数,而不能用_countof,因为_countof是用来计算数组的,是用总共的空间除以单个元素的空间。

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

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

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

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

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

所有的C语言函数在我们的VS开发的时候,你都要看一下帮助,有宽的,有窄的,还有自适应的TCHAR类型的。

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

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

为了将入职日期这个字符串转换为CTime类型,我们查看了CTime类的帮助,发现没有合适的成员函数;
我们又看了COleDateTime类:
在这里插入图片描述

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

在这里插入图片描述

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

只要你有年月日时分秒的东西带进来,就给你生成一个COleDateTime对象,这个函数具有将字符串转换成时间的功能,它内部有自动拆分的功能。

用CTime类型的话就很麻烦了,你要想把带进来的字符串拆分成年、月、日、时、分、秒,再把它们存入到CTime对象里来,这是一个很麻烦的过程。

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

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

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

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

果然,tDate变成了非0的数字,时间部分是空的,只把日期部分(年月日)合成一个数字放在这里,这是一个准确的时间。

这个COleDateTime类的核心数据成员:
VS2015之博大精深的MFC项目开发(二)_第215张图片

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

double是8个字节;
也就是说COleDateTime这个类的对象占12个字节。

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

可以看到保存的Worker.dat文件的大小是52个字节。

这是用二进制来看的,前面的4个字节0x000003E9的十进制就是1001,也就是我们输入的工号。

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

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

上图选中的8个字节就是COleDateTime对象中的DATA类型的m_dt数据成员,占8个字节(低4字节是时间部分为空);最后的4个字节是该对象中的m_status数据成员。


5、MFC07-2:继续完善员工信息管理项目开发

5.1 实现加载功能

每读取出来一行数据,就把它放到列表中。
VS2015之博大精深的MFC项目开发(二)_第220张图片

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

从文件中读取一个结构体(SInfo),只要Read的返回值每次都是一个完整的结构体,不是半个结构体,就可以继续循环。

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

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


5.2 把日期类型转换为字符串

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

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

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

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

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

我们发现这个日期带有星期,我们如果不开心使用这个类的Format,不想使用这种文字日期格式的话,我们就要手工的去Format了,就用CString的Format,它的Format是简易的Format;
这里我们还是用这个类的其他Format重载形式看看。

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

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

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

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

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

我们用CString的Format,它的Format是简易的Format,用它的话就比较累些:
VS2015之博大精深的MFC项目开发(二)_第234张图片

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

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

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

让软件一启动的时候自动加载:
VS2015之博大精深的MFC项目开发(二)_第238张图片

再把加载按钮给它删掉:
VS2015之博大精深的MFC项目开发(二)_第239张图片

我们还可以在软件退出的时候,提示用户是否需要保存。


5.3 实现修改功能(单行)

我们在修改的时候一般不改编号,而且我们多数情况下只对第一个选中的进行修改。
VS2015之博大精深的MFC项目开发(二)_第240张图片

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

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

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

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

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

我们看到GetSelectedCount返回值是3,这个可以用来判断是否有选中的行。
不用这个方法,我们用GetFirstSelectedItemPosition函数的返回值来判断也是可以的:
VS2015之博大精深的MFC项目开发(二)_第246张图片

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

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

我们看到GetFirstSelectedItemPosition函数的返回值就不是空了,它的值是3;接着往下执行的话GetSelectedCount的返回值nSel的值是2。

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

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

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

上面实现的是单选的修改。


5.4 实现多行修改

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

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

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

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


5.5 实现删除

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

大家现在如果要删除多行的话,用刚才修改里面的那个循环,保证会出问题,为什么出问题呢?
VS2015之博大精深的MFC项目开发(二)_第257张图片

在你多选的行为1、3、4行的时候,循环中删除了第1行的时候,下面的2行就成了1行,3行成了2行,4行成了3行,就可能删串了;然后你本来该删3行的,结果变成了删的是4行;当你要删4行的时候,这一行成空行了。
整个删除的过程会往上串,如果你没考虑串的这个问题的话,最后你会发现乱了,没有达到你的预期:
在这里插入图片描述

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

第一个删除是对的,但是当你删除了第一个之后,直接就跳到删1005去了,把1004给跳过了:
在这里插入图片描述

在这里插入图片描述

把1004给漏下了。

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

现在是要删除1003、1005、1007。

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

删除1003是对的,但是删完了1003之后1005往上串了,如果你把1006删除了,就会串到1008去了,删错了1008:
VS2015之博大精深的MFC项目开发(二)_第261张图片

漏删了1005和1007:
VS2015之博大精深的MFC项目开发(二)_第262张图片

解决方法:
用两个循环,先用一个循环把要删除的记录到一个数组里,然后再倒着删除比较好,从底下往上删除就不会出现串的问题了。

如果你不想从下往上删除,你就用一个循环,那就需要调整代码,要删除的第一个序号不减,之后你每删除一次就要把得到的pos序号减1,这就需要你好好想想该怎么写这个算法。


5.6 实现退出功能

在这里插入图片描述

我们在类中添加一个BOOL类型的成员变量,用来记录数据是否被改动过了:
VS2015之博大精深的MFC项目开发(二)_第263张图片

在这里插入图片描述

也可以在OnInitDialog函数这里让它等于FALSE也是可以的,软件启动之后等于FALSE就行了。

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

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

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

在添加、删除(确实删除成功了)、修改(确实修改成功了)函数里面给它赋值为TRUE。

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

还要记得,如果保存成功了,要把这个标志修改为FALSE:
VS2015之博大精深的MFC项目开发(二)_第268张图片

也就是说,如果你在退出之前,主动点击了保存按钮,已经保存过了(在保存的地方把修改标志变成FALSE),这种情况下你退出的时候就不需要再保存了,你已经保存过这个修改了,然后你在退出时它就不用提示了,直接退出即可。


6、MFC07-3:MFC类库封装原理

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

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


6.1 在C语言中我们是如何使用时间的

我们对C语言的Time和MFC的CTime类进行一个对比,在这个基础上我们自己把这个C语言的Time封装成一个类。
VS2015之博大精深的MFC项目开发(二)_第271张图片

在C语言中获取当前时间是很痛苦的:
VS2015之博大精深的MFC项目开发(二)_第272张图片

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

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

根据你的操作系统是64位还是32位,这个time_t会自动选择,编译器会根据你的机器自动选择64还是32的,你直接用就可以了。

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

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

这串数字你通过肉眼根本是识别不出来年月日时分秒的,这个数字每过一秒会增加1下。

这个time函数既可以从参数返回结果,也能从函数返回值返回结果:
在这里插入图片描述

拆分函数是localtime:
VS2015之博大精深的MFC项目开发(二)_第277张图片

struct tm 这个结构体就包含了年月日时分秒。
也可以使用安全版本的函数:
VS2015之博大精深的MFC项目开发(二)_第278张图片

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

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

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

这个tm_year的115,是指从民国时间开始算起的:
VS2015之博大精深的MFC项目开发(二)_第282张图片

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

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


6.2 使用MFC类库中的时间族CTime

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

CTime的核心数据成员就是m_time:
VS2015之博大精深的MFC项目开发(二)_第286张图片

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

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

一个用类的获取时间的方法,一个是用C语言函数获取,很显然C语言比较笨拙。


6.3 用C语言把你的生日存入到一个时间对象里

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

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

这个mktime函数是localtime函数的反函数,它可以生成你指定的这个time_t结构。

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

测试mktime函数后,我们就可以获取上图界面中填入的生日,存入tm结构,再通过mktime生成time_t结构;你还可以把数据存入文件中就比较完善了。


6.4 再看看MFC类的存入时间的方法

在这里插入图片描述

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

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

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

你如果用C语言来做的话,还得把时间解析出来,就比较笨了。

你可以通过程序界面上的控件,把获取到的年月日时分秒存入到日期对象里:
VS2015之博大精深的MFC项目开发(二)_第295张图片

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

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

所以我们这个CTime这个类,无论是存入时间,还是获取当前时间,还是从其中取出年月日时分秒,都非常方便。


6.5 自己封装一个Time类

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

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

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

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

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

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

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

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

使用localtime的安全版本localtime_s:
VS2015之博大精深的MFC项目开发(二)_第306张图片

把不好用的东西放在内核里封装起来,做成好用的东西。

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

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

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

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

测试用我们自己封装的类:
VS2015之博大精深的MFC项目开发(二)_第311张图片

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

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

获取当前时间函数,我们直接返回time(NULL)的返回值就可以了,time函数返回的time_t 时间句柄会自动构造CMyTime对象。

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

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

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

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


7、MFC08-1:开发一个记事本软件

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

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

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


7.1 讲解初始化消息OnInitDialog

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

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

我们看到上图的OnInitDialog这本来是一个消息,却没有出现在上面的BEGIN_MESSAGE_MAP位置那里,这是因为这个函数被CDialog类给做成在基类中去截获这个消息,然后再以虚函数的方式反调到派生类来;

  • OnInitDialog
  • OnOK
  • OnCancel
    总共有这3个虚函数,这3个虚函数你都不需要在消息映射中去添加,你要添加的话,你可以在类向导的虚函数中添加就行了:

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

本来这3个消息,有两个是按钮消息,一个是初始化消息;
我们从上图可以看到,现在这个初始化消息已经是在虚函数中添加了。

对于每一个窗口有两种回调方式,第一种回调就是消息映射,消息映射是最基础的回调方式;
在消息映射的基础上呢,有些函数呢它又通过虚函数回调回来,比如说OnOK,这个本来也是按钮消息,是ID_OK的按钮消息,还有一个是OnCancel也是系统消息,原来这3个函数都是系统消息,双击一下就可以编辑这个消息的处理代码,但是都被基类把消息给提前处理了;
默认按回车键会调用OnOK把该对话框关闭,正常来说按ESC是不会关闭记事本的,所以这里我们把调用基类的OnOK和OnCancel都注释掉,把这两个按钮的缺省动作都去掉:

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

今后要退出时要从菜单退出,OnOK和OnCancel这两个地方不退。


7.2 添加菜单资源

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

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

在这里插入图片描述

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

如果以前的工程中有现成的菜单,我们想把它添加到我们现有的工程中的话,比如以前用VC6做过的一个工程;
或者一个现成的exe的资源,比如系统Windows目录下的notepad.exe:

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

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

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

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

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

我们看到这里果然有菜单,把这个菜单给它拿出来那该多好啊,我们试着用VS2015打开这个资源:

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

我们发现好像不行,如果VS也能像VC6那样把资源提取出来就好了:

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

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

我们发现VS没有提取资源的功能。

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

VC6也无法导出这个资源,我们用VS2015导不进来,也无法从文件、打开来打开这个资源;
经过反复的试验,我们可以先用VC6另建一个对话框工程,把这个有菜单的资源添加进这儿新VC6工程中,然后再从这个工程里把这个资源弄出去:

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

用VC6打开notepad.exe这个执行文件的资源:

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

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

把这个执行文件的菜单从到我们新建的VC6工程里面来:

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

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

保存一下。
再用VS2015添加现有项,添加刚才那个VC6新工程的.rc资源文件:

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

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

把VC6的菜单资源拖动到我们工程里面来。

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

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

然后就可以把上图这个添加的VC6.rc删除了。

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

这就是将外部资源,尤其是执行文件的资源,拖入到我们的工程中的方法。
这样的话已经有很多资源编辑好了,我们只要把自己的资源删掉,留已经做好的资源,然后就可以在我们对话框中把这个菜单添加进来:

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

把添加的这个菜单的ID改一下(方便识别而且易用),就是我们自己的菜单了。

再把菜单添加到我们的对话框里:

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

这个菜单里的ID不好看,我们把菜单中的那些命令的ID修改系统中已有的ID,这样方便识别而且易用,编译运行后:

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

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

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

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

退出和关于这两个菜单项的系统ID一般是ID_APP_开头的。

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


7.3 实现菜单退出项的功能

像这种菜单是如何生成一个消息映射函数呢?只要你选择CNotepadDlg这个类,或者选择这个对话框资源,打开类向导:

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

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

这个类向导能做几项功能:
当你直接选择消息的时候,这个消息是主窗口消息,包括LBUTTONDOWN、MOUSE_MOVE等;

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

虚函数也是主对话框的,一般不是控件的回调,都是主对话框的事情。

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

命令里有很多是按钮、菜单或者说是工具栏;
在windows开发中有3种能够发出命令的东西,一是菜单,二是按钮,三是工具栏快捷键可能也能发出命令。

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

我们在win32下是由自己去做这种COMMAND消息的截获,在我们MFC中,如上图所示只要选择了左边的命令ID,双击COMMAND就会自动生成一个OnAppExit消息处理函数:

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

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

这个EndDialog将IDCANCEL参数代进去的时候,它将从应用程序实例CNotepadApp的InitInstance传出来;
我们把上图中的启动函数清理一下,里面只留一个对话框的弹出:

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

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

这里我们干脆把菜单项的ID传进去,DoModal的返回值通过这个EndDialog传入的参数可以知道,你是按什么方式关闭的这个对话框,是按确定,还是取消,还是某个菜单项;
也就是说EndDialog你放入什么,DoModal就传出什么,有时候用于对点击哪个按钮退出的判断。


7.4 记事本的文件拖入打开功能

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

我们首先修改整个对话框的属性Accept Files,让它支持拖放文件的方式来打开文件,这样的话,整个对话框都能拖入文件了:

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

我们的对话框支持拖放后,为了实现拖放打开文件,是要编码的,要对它相应的消息映射函数进行处理:

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

当你把文件拖进去,鼠标不弹起,不叫Drop,鼠标弹起来了,才叫Drop。

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

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

这个hDrop句柄可能是不止一个文件的集合,比如说你拖动好几个图片往Photoshop里扔;
通过这个句柄可以取出好几个文件的文件名,或者是一个文件的文件名。

iFile是说,当你代入-1的时候,你是要求当前有多少个文件被拖入了;
比方说总共拖进来5个,如果你代入的是0到4之间这5个数中的一个数,该函数将把对应的文件名拷贝到lpszFile参数里。

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


对拖入的每个文件名进行提取

这里我们拖入5个文本文件:

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

虽然真正的记事本软件不需要循环,记事本只能打开一个文件,但是这里我们通过一个循环来熟悉了解DragQueryFile这个函数;如果你做的是多文档编辑的软件,那么你就要用循环。

这里我们再修改代码,不管你拖入几个,我就只管打开第一个就够了,其他的都不管了:

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


8、MFC08-2:继续开发记事本软件

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


8.1 对话框窗体的属性(外观、行为)

在这里插入图片描述

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

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

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

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

设置Border为None的话可麻烦了,这是做子窗口用的,它往往放在一个分页窗口里,每个页面都是这样的子对话框;有些软件的关于对话框就是一副图片的样式,None的话就没有标题;
这里我们设置Border为Resizing恢复回去。

在这里插入图片描述


8.2 编辑控件的风格

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

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

编辑框的Accept Files即使设置为True,编辑框也接收不到消息,因为Accept接收是在主对话框里接收的,消息是送到主对话框的;
那你这里的编辑框的Accept Files要设置成True的话,它的消息要在这个控件类里接收,也就是说你要做一个CEdit的派生类才能接收到这个消息。

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

这个No Hide Selection的效果如下图所示:
VS2015之博大精深的MFC项目开发(二)_第380张图片

当焦点跑到另外一个对话框的时候,前一个窗体中选中文字仍然处于选中状态,这个选中仍然有效。

我们也创建一个关于对话框:
VS2015之博大精深的MFC项目开发(二)_第381张图片
VS2015之博大精深的MFC项目开发(二)_第382张图片

并给它添加一个关联的类:
VS2015之博大精深的MFC项目开发(二)_第383张图片

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

我们在主对话框类上打开类向导,并给ID_APP_ABOUT这个菜单命令添加一个消息响应函数:
VS2015之博大精深的MFC项目开发(二)_第385张图片

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

并把这个关于对话框的属性No Hide Selection设置为True,这个时候里面选中了一些文字的话,当你的焦点跑了之后,选中的文字仍然处于选中状态:
VS2015之博大精深的MFC项目开发(二)_第387张图片

在这里插入图片描述

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

我们一般不用Auto HScroll,这是个单行的控件,它会自动横向滚动,当你输入的内容太多的时候会自动往右滚,只能在一行上输入显示文字(密码风格只能是单行的控件才能使用);
我们一般用Vertical Scroll,可以让控件内容自动换行向下滚动。

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


8.3 完善编辑框的功能

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

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

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

在这里插入图片描述

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

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

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


8.4 添加一下close消息处理

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

当你点击系统关闭按钮的时候,或者当你按Alt+F4的时候,由于系统的这个对话框的基类CDialogEx::OnClose函数会自动转入到OnCancel,而我们已经设置OnCancel不工作了,是为了防止你按ESC键把我的记事本给关闭,所以这里就把基类CDialogEx::OnClose函数注释掉:

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


9、MFC08-3:记事本软件功能完善

9.1 粘贴功能

在这里插入图片描述

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

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

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

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

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

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

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

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

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

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

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

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


9.2 实现粘贴功能

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

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

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

我们发现鼠标右键可以粘贴,但是菜单里的粘贴无效,并且选中一部分文字后删除也无效。

我们再看看撤销的功能看看能不能实现:

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

我们测试发现撤销功能可以工作。

那为什么那几个菜单不可用呢?

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

我们按照上图所示,把那几个菜单的Grayed属性设置为False(为True的话是灰色不可用的)。


9.3 全选功能

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

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

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

在这里插入图片描述

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

测试后发现鼠标点击全选菜单工作正常,但是它的Ctrl+A这种快捷键功能并没有实现,因为快捷键是一个专门的技术,我们必须要在资源中添加快捷键,但是添加了快捷键之后也不见得能够生效,这是一种专门的技术。
这里我们先暂时把快捷键资源添加上来,先放在这里:

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

在这里插入图片描述

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

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

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

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

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

即使添加了这个快捷键,它还是不能使用,为什么呢?大家可以自己琢磨搜索LoadAccelarator研究一下,你要加载快捷键,还要在对话框里设置上快捷键,才能够实现这样的功能,这个技术以后大家慢慢研究。

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


9.4 插入日期

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

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

要实现上图的功能,先得取当前时间;
推荐使用COleDateTime,而不推荐CTime:

在这里插入图片描述

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

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

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

但是,我们测试后发现,选中一部分文字后,点击日期,会把编辑框中所有文字覆盖掉了,都丢失了,和正规的记事本不一样,说明SetDlgItemText这个函数很显然是不对的。

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

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

第2个参数是指,是否要重新恢复原来的文字。

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

设置一下对话框的字体:

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

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


9.5 简介消息映射

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

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

其实消息映射机制我们现在也都知道了,就是在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间,将一个ID、一个消息(COMMAND、SIZE、CLOSE)与一个函数关联;

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

或者将一个消息(ON_WM_PAINT)与一个固定的函数相关联,比如上面这个WM_PAINT消息,它就是绘图消息,它就必须和OnPaint关联,它是一消息、一函数;

在这里插入图片描述

有些呢是一消息加一ID、再一函数,那个函数的名字就是死的了,因为它必须根据这个ID生成这个函数名,有些是跟那个ID无关的,比如说ON_WM_CLOSE,这个消息在消息映射中它必然是映射到这个死的OnClose函数名,绝对不可以换,你把这个OnClose函数名改变、改成小写的、大小写搞反一个,它都找不到那个函数,这就是消息映射。

总之,你只要知道,一个消息可以关联到一个函数上就可以了。


9.6 剖析消息映射机制

VS2015之博大精深的MFC项目开发(二)_第441张图片
大致的消息映射,就是刚才所说的那些理论,就是一消息、一ID、一函数,或者一消息、一函数。

Win32没有消息映射,Win32是使用消息处理函数,统一把所有的消息都在一个消息处理函数中进行分流;
而我们的MFC呢是系统帮你把内部的内容分流好了。

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


DECLARE_MESSAGE_MAP、BEGIN_MESSAGE_MAP

VS2015之博大精深的MFC项目开发(二)_第443张图片
像上图头文件中最后一句话DECLARE_MESSAGE_MAP是什么意思呢?

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

这句话其实是隐藏了很多内容的,我们把它还原一下:

VS2015之博大精深的MFC项目开发(二)_第445张图片
而实现文件中的BEGIN_MESSAGE_MAP这一句话,实际上带了一堆东西:

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

VS2015之博大精深的MFC项目开发(二)_第447张图片
我们也罢BEGIN_MESSAGE_MAP还原一下:

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

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

AFX_MSGMAP_ENTRY这个结构体里面包括了消息、消息ID和函数地址,这就是一个消息对应一个函数地址(函数指针):

在这里插入图片描述

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

就是AFX_MSGMAP_ENTRY这样一个结构体在GetThisMessageMap这函数内定义了一个数组,而且是静态的数组,加上static就代表这个_messageEntries数组的位置放在了全局区,它的有效性是长期的,甚至在程序启动的时候这个数组就可能被初始化了,编译之后把上图这些内容都编译到数组里来了。
所以从上面可以看到,这就是一个消息对应一个函数。
这些结构体初始化好了,也就是填充好了这个AFX_MSGMAP_ENTRY结构体,放在_messageEntries数组里,这个数组里可能是100这种结构体,或者几个结构体。
这样我们就看到了,每个窗口类在全局区定义好了自己的一个结构体数组,这个结构体数组就反应到了,在上层比如基类指针如果获取到了这个数组地址的时候,就会把这个数组里的消息对应的函数地址取出来了。

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

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

我们看到GetThieMessageMap这个函数返回的是一个结构体地址,其实它主要返回的就是_messageEntries指针。

在这里插入图片描述

messageMap也是一个结构体,AFX_MSGMAP这个结构体里面放了两个指针,这个lpEntries指针只要返回去之后,它就能够沿着这个lpEntries(其实就是_messageEntries数组)找到结构体的地址。

在系统内部有这个窗口的消息循环,它就是在每一次消息循环的时候,把对应的消息在另一个循环里对_messageEntries这个数组进行遍历,找到该消息对应的函数进行调用。

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

我们刚才手动添加了一个WM_MOUSEMOVE消息映射,但是还没有该消息对应的OnMouseMove函数实现,所我们给窗口类手工添加一个OnMouseMove和这个消息去匹配:

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

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

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

CEdit类成员:

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


10、MFC09-1:读取文本文件的软件开发

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

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

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

如果发现拖拽功能失效,看看对话框的Accept Files属性是否为True。

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

我们拖入的文件大小是210字节,因为我们这里是unicode字符集,每个TCHAR占2个字节,sizeof(_T(‘\0’))的值为2,但是从上图监视发现,sFile[nRet] = _T(‘\0’);这里的nRet的值却为210,这是错误的,'\0’的索引应该为105附近才对。
整个的读取过程都是不太正确的。


10.1 文本编码格式(UTF-8、UTF-16)

我们要知道文件一般分为3种,有三种编码格式:

  • ANSI
  • Unicode
  • UTF-8

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

我们假设拖入的文本文件编码格式为ANSI,修改代码如下:

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

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

我们看到这肯定还是文本格式有点问题,我们用VC6以二进制格式来打开拖入的文本文件,看看文本的头会不会是:

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

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

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

我们看到前面明明是等号,但是用VC6以二进制格式打开该文件,开头的3个字节却是EF BB BF,之后才是一堆3D这个等号的ANSI码,那么前面这3个字节到底是什么?

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

读取文本的过程,我们要分为3种来读取,即我们要区分3种文件,有3种文件要读取,所以我们用3个函数来读取。

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

在这里插入图片描述

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

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

通常见到的就是UTF-8和UTF-16这两种格式,UTF-16就是Unicode,我们重点是研究UTF-8和UTF-16格式的文件。

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


10.2 读取UTF-8转换为Unicode

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

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

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

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

这个CFile::Seek函数的第二个参数意思就是,你是距离头,还是距离尾,还是距离当前。

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

其实我们这里只需要把文件转换为Unicode编码格式就够了,不需要转换为UTF-8。

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

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

经断点调试发现,前面的中文是对的,然后是一段乱码,接着又是一段正确的中文,然后又是一段乱码,可能是由于我们是一段一段读取的,中断的地方有问题,比如一个中文是两个字节,正好把这两个字节断开了,半个汉字一转码后,显示肯定乱码。。。。。。
所以,如果文件不是特别巨大的话,我们可以把整个文件完整的一次性读取完毕。

在这里插入图片描述

记得最后默认读取ANSI的函数那里,要用Seek重新定位到头部,因为ANSI没有编码头。

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


11、MFC09-2:对话框常用的回调函数

11.1 读取Unicode文件

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

这里读取到的字符数要算一下,因为这里的TCHAR占2个字节,如果读取到的是10个字节,那么也就相当于是5个字符。

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

由于CFile::Read的返回值是以字节为单位的,它不是以你的TCHAR为单位的,因为我们当前系统就是Unicode,也就是UTF-16,这个地方的TCHAR是2个字节的,所以Read读取到的长度要除以2:

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

在这里插入图片描述

在这里插入图片描述

Windows的记事本软件的另存为,可以选择编码格式,Unicode就是UTF-16,Unicode big endian就是UTF-32了。


11.2 对话框常用的回调函数

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


11.2.1 WM_CREATE和WM_INITDIALOG消息

为了判断WM_CREATE和WM_INITDIALOG的处理顺序,我们给对话框添加一个CListCtrl控件进行测试,先看看在WM_CREATE消息种是否能够初始化CListCtrl该控件:

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

WM_CREATE是指我的父窗口已经创建好了,WM_INITDIALOG它不止是父窗口创建好了,而且子控件也创建好了,就等着你去使用它了;
所以你要是想在WM_CREATE对CListCtrl控件进行操作,可能会造成程序崩溃:

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

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

很显然,对于子控件的操作,必须在当你的对话框程序里面的初始化这部分消息开始的时候,包括控件已经创建好了,你才能够去调用这些控件。

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

总之,在WM_INITDIALOG这个消息来的时候,对话框内的资源都已经按照模板中指定的控件都已经创建好了,可以使用了。
对对话框内部控件的初始化操作一般放在WM_INITDIALOG这里。

我们再试试对于主窗口的图标设置放在WM_CREATE处理函数里面是不是可以使用:

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

我们发现,对主窗口的操作放在这里也没问题。

VS2015之博大精深的MFC项目开发(二)_第491张图片
我们再看看PreSubclassWindow虚函数是在什么时候被执行:

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

这是一个虚函数回调,我们来看看它发生在OnCreate的过程之前,还是发生在OnInitDialog之后。

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

我们发现,先调用PreSubclassWindow,然后才去调用OnCreate,这个函数就很强大了。

我们再试试对主窗口设置的函数放在PreSubclassWindow函数里看看是否可以:

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

说明在这里、在OnCreate、在OnInitDialog设置主窗口图标都是没问题的;
对主窗口的操作,这3个函数都可以,但是对子窗口的操作只有OnInitDialog中执行。


11.2.2 WM_CLOSE和WM_DESTROY消息

接下来我们要看一下关闭过程,首先要介绍的是系统关闭过程。
WM_SYSCOMMAND这个系统命令中包含了:还原、移动、改变大小、最小化、最大化、关闭,就是在下图系统菜单中你能看到的东西,都属于WM_SYSCOMMAND的管辖范围。

VS2015之博大精深的MFC项目开发(二)_第495张图片
WM_CLOSE是系统消息中的CLOSE关闭分支,也就是说WM_CLOSE也是来自于WM_SYSCOMMAND里面总共有6个分支其中的一个分支。
WM_CLOSE最后会进入OnCancel虚函数回调,本来它是个按钮消息,被系统接管过去之后变成一个虚函数回调,当你真正关闭的时候有一个WM_DESTROY消息发生,当WM_DESTROY消息发生的时候就已经无法取消这次关闭了;
当WM_CLOSE消息发生时,或者OnCancel执行时,我们可以取消这次关闭的任务;但是到了WM_DESTROY消息发生时,已经正在摧毁窗口了,是不可以回头必须关闭了。


11.2.3 测试WM_SYSCOMMAND消息

我们做个测试,模仿360或者鲁大师,点击窗口右上角,或者ALT+F4关闭窗口,但其实并没有真正关闭程序,只是隐藏起来了。

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

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

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

第一个参数就告诉你是6种动作中的哪一种,虽然从上图可知不止这6种动作;
如果我们在OnSysCommand函数当中不想关闭的话,我们想把这个窗口隐藏,或者最小化:

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

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

在这里设个断点,编译运行程序,当我们ALT+F4的时候进断到这里了,继续运行就将该窗口最小化了;但是当执行最后一行的时候,实际上这个窗口还是关闭了,也就是说走基类的OnSysCommand的话还会执行缺省任务,缺省任务的意思就是如果刚才是关闭任务的话它还继续关闭。
这里实际上我们不想关闭:

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

因为我们还没有实现托盘功能,如果将该窗口隐藏(SW_HIDE)的话,任务栏看不到该程序,我们就只能通过任务管理器强制关闭该进程。

当你鼠标右击窗口标题栏点击弹出的关闭,或者ALT+F4关闭窗口的时候,这个过程它最先进入的就是OnSysCommand这个消息。


11.2.4 测试WM_CLOSE消息

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

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

经过上图修改下断点调试,发现先调用OnSysCommand,然后再去调用OnClose,这样的话呢,我们有的时候就干脆不要这个OnSysCommand消息了,我们可以在类向导种删除OnSysCommand消息:

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

删掉这个处理程序,它会把头文件中的函数头,实现文件中的函数实现都删除掉,另外还有一个地方被删除掉了,就是消息关联的地方被删除掉了:

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

我们可以在OnClose中专门去管关闭时的消息,就不需要if分支、判断ID了:

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

这时候你点右上角的关闭按钮、鼠标右击标题栏点关闭、或者ALT+F4的话,它并没有真正的关闭,而是最小化了,除非你点击取消按钮才是真正的关闭。


11.2.5 OnCancel虚函数

第3个关闭流程,假设你不是没有在OnClose进行最小化处理,你是真正要关闭了,就是还有一个地方可以截获这个关闭消息,就是OnCancel这个虚函数:

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

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

你在OnClose和OnCancel中下断点,可以观察到,会从OnClose调用到OnCancel。


11.2.6 WM_DESTROY消息

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

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

实际上走到这个消息的时候,窗口的句柄还在,在这个时候你可以执行列表控件的数据保存,并且子窗口都可以使用,唯一的就是它不可以回头了,不能取消关闭了;
而且走到这一步你不用隐藏它了,它自身已经隐藏了,窗口已经处于不可见状态了。

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

走到这个消息确实是不能再回头了,包括窗口都已经消失了,假设运行该程序后我点击确定按钮,窗口在任务栏中已经没了,只有这个弹窗还能出来。

包括你在OnCancel函数中添加上基类的OnCancel,不管你从哪里执行的关闭对话框的动作,走到了OnDestroy这一步的话是最后一步,整个窗口都没有了:

在这里插入图片描述

在这个时候你还可以去执行对列表控件内的数据进行循环保存还是可以的。

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

因为在这里你可以使用列表进行循环,而真正的析构函数是不能操作这些列表的,因为真正的析构函数,列表的控件都已经被摧毁了。


12、MFC09-3:消息传递函数

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


12.1 SendMessage函数

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

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

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

现在你在按钮上面双击,是不会建立关联的函数了,那是MFC的功能,MFC双击一个界面中的按钮,它就能建立消息映射函数;
我们在win32下(没有MFC的情况下)必须是在回调函数中去做消息的分支处理。

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

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

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

在这里插入图片描述

在这里插入图片描述

SendMessage就是模拟系统来发送这种关闭,或者是任何消息都是可以模仿发送出来的。

我们还可以用SendMessage朝一个系统内的其他的进程,只要用FindWindow找到这个句柄,就可以关闭其他软件的窗口,也是可以的。

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

当这个窗口是阻塞的状态,或者是发送的过程,对方不肯关闭,这个SendMessage是阻塞的,等待你对记事本的操作,所以SendMessage是一个阻塞型的操作,要等你把它处理好它才走,或者等你返回一个结果它才走。


12.2 PostMessage函数

PostMessage是异步的,它是不等的,它告诉你一声就走了,就是说,你要记得把那个窗口关闭啊,它不会像SendMessage那样你要不关闭我就不走,我就等你关闭,什么时候关闭我才结束,它会卡在那里,SendMessage等待消息被处理完了之后才返回;
PostMessage就是把消息放在对方的消息队列里,不管消息处理的结果如何就返回。
SendMessage是必须等你这个消息处理完之后才返回。

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

一个是阻塞型的,一个不是阻塞型的。
如果是SendMessage,它就要等人家处理,人家不处理它就不干;
PostMessage就不管你那一套,你去处理与不处理,我这里告诉你了,我就完成任务了,后续它就不等待。

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

在这里插入图片描述

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

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

在这里插入图片描述

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


12.3 Win32下测试SendMessage的返回值

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

在这里插入图片描述

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

一般情况下,我们平时开发的时候自定义消息大多数都是加个100或200就够了(WM_USER + 100)。

在这里我们来发一个自定义消息,你要把传进来的两个参数wParam和lParam相加的结果返回:

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

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

我看看我在SendMessage这里等待,看它的返回结果是不是UM_ADD分支返回回来的结果,在这两处设置断点;
我们不再往记事本里发送消息了,我们往自己窗口里发送,并且在自己窗口里截获这个UM_ADD消息;由于wParam是一个无符号整数,lParam是有符号整数,所以我们调整代码,把负数放在后面:

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

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

理论上SendMessage必须要等待这两个数字送过去之后,在UM_ADD分支那里把两个数字相加的结果要返回来,但是我们发现返回的结果res还是等于0。
在Win32下SendMessage和PostMessage的这种返回值还不好观测;
在Win32下一直截获不到SendMessage的返回结果。

我们去到MFC工程下,再来测SendMessage的返回值,在MFC下是如何截获SendMessage发送来的用户消息或者系统消息。


12.4 MFC下测试SendMessage的返回值

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

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

上图function就是Win32 API,而method就是MFC。

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

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


在MFC中自定义消息应该怎么建立呢?

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

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

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

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

ON_MESSAGE是自定义消息的宏。

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

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

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

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

我们可以看到用SendMessage发送的自定义消息的返回值正确返回回来了。

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

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

假设消息处理函数里有一个循环,需要等待2秒才处理完,SendMessage就要等2秒才能返回,是必须等你算出结果后我才走,而PostMessage半秒都不用等直接就走了。

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

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