1.前言
在前面我们写控制台项目时,整个思路都很简单,顺着写就完了,缺啥我们就写啥。
但到了窗口程序这里就不一样了,因为它的运行机制是消息循环。
所以到这里我们就得开始转化写代码的思路:需要响应什么消息,我们就写什么代码!
比如我们想要控制程序窗口的大小,那我们就得响应窗口大小变化的消息,其它的类似。
甚至可以说,MFC程序其实就是在面对消息编程。
但不用担心,这些消息并不用你记住,只需要知道有这个东西即可,需要的时候直接在MFC里面找,还是非常方便的。
2.MFC消息的使用
老规矩,还是先建一个MFC的项目吧:
这次的名字为:day12–USE_MFC,中间的选项和上一节一样即可。
既然是面向消息编程,那我们就先来看一看有哪些消息,右键项目,可以进入类向导:
同时注意上方的项目、类名不要选错了:
类名为Dlg
结尾的就是窗口类,而我们一般也是为窗口添加消息响应。
然后我们就可以看一看这个窗口有哪些消息:
可以看到,这些消息基本都是WM_
开头的,即Windows Message
,然后后面就跟着消息的名称。
比如常用的WM_CLOSE
消息,就是程序关闭时的消息,如果我们想要响应这个消息也很简单,点击一下这个消息,然后点击右上角的添加处理程序,就会自动生成该消息的处理代码:
然后我们回到该类中,可以看到代码中添加了三个东西,首先看到的应该是实现函数:
然后还有消息映射:
最后是头文件中的函数声明:
知道这些的目的是,当你不想要这个函数了,你需要亲自把它们都删除掉!
当然你也可以直接在类向导里面去删,只不过其默认是将代码都注释掉,而不是直接删除。
然后我们试着在这个函数里面写一些我们自己的函数:
然后运行程序,点击右上角的叉关闭窗口,退出程序时就会弹出一个对话框:
是不是发现用MFC写程序确实非常方便!
这里注意一下我写的代码:
AfxMessageBox
是MFC自己封装的一个对话框窗口,只能MFC
里面用,windows
提供的对话框函数为MessageBox
,可以自己查查该怎么用。L""
:由于MFC
默认使用的宽字节字符集,所以MFC
里面的函数默认都只接受宽字节字符串,如果想要用多字节字符集,可以自己在项目属性里面更改。
同时还有另外一种写法为:_T("")
,这是一种通用的写法,它会在宽字节字符集下变为L""
,多字节字符集下去掉L
,其本质就是定义的一个宏,可以用前面我们使用的方法自行查看!
void Cday12USEMFCDlg::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
AfxMessageBox(_T("你正在关闭对话框")); //使用更加通用的方式_T("")
CDialogEx::OnClose(); //调用父类的默认处理函数,用于关闭窗口
}
这里再介绍几个常用的消息:
鼠标消息 | 作用 |
---|---|
WM_LBUTTONDOWN | 鼠标左键按下的消息 |
WM_LBUTTONUP | 鼠标左键松开的消息 |
WM_LBUTTONDBLCLK | 鼠标左键双击消息 |
WM_RBUTTONDOWN | 鼠标右键按下的消息 |
WM_RBUTTONUP | 鼠标右键松开的消息 |
WM_RBUTTONDBLCLK | 鼠标右键双击消息 |
WM_MOUSEMOVE | 鼠标移动的消息 |
这个很好记,就是几个常用单词的缩写,左是Left
,右是Right
,即首字母嘛,然后button
为按钮,DWON
为下,UP
为上,DBL
为double
双倍,CLK
为click
点击。
窗口消息 | 作用 |
---|---|
WM_DESTROY | 窗口摧毁时消息,此时窗口无法复原 |
WM_CLOSE | 窗口关闭的消息,可以通过不执行CDialogEx::OnClose(); 达到不关闭窗口的目的 |
WM_SIZE | 窗口大小改变的消息 |
上面是一些比较常用的消息,其它更多的消息可以自己慢慢遇到了再看。
3.虚函数
前面介绍了消息,我们还可以在旁边看到虚函数这一项:
虚函数就是前面提到过的类的成员函数,前面加了virtual
关键字的。
因为我们的类都是继承于MFC的标准类,所以我们就可以重写其基类的函数。
这里注意一下用词:重载
与重写
有区别,简单来说,函数名相同、参数不同为重载,而在父子类之间函数名与参数可以完全都相同,也就是重写。
我们这里可以看到父类标准对话框的函数还是有很多的,比如我们前面提到过的OnInitDialog
函数也在里面。
这里添加一个我们可能常会用到的虚函数OnOk
:
使用方法与前面的相同,这个函数主要用于退出应用程序。
注意:一定要确定自己选择的是正确的项目与对话框类,因为如果我们生成了关于对话框,那每次进入类向导时,其默认选择的对话框类就是那个关于对话框的,这会导致后面的操作无效。
与OnCancel
所起的作用基本相同,主要是方便我们区分用户是用哪种方式退出程序,以便于做出不同的处理。
当然,你也可以通过注释掉调用父类的函数,这样它就不会退出程序了:
void Cday12USEMFCDlg::OnOK()
{
// TODO: 在此添加专用代码和/或调用基类
AfxMessageBox(_T("通过Ok关闭对话框"));
//CDialogEx::OnOK();
}
生成的三个代码地点前面提到过,这里不再多说,然后我们运行试一试:
这里我们通过按确定,想要退出程序,但弹出一个窗口。
按了确定键却不退出,这就是因为我们注释掉了调用父类函数的代码。
其它虚函数大家也可以自己都试一试,不明白的网上搜就是了。
除了上面所说的消息与虚函数,我们还可以看到:
命令这一项不用管,它用于生成控件消息函数的,但我们有更简便的方法,一般不用它。
然后后面的成员变量与方法,就是当前我们选择的这个类中的成员变量与成员函数,一般也用不到,大部分时候我们都是直接在代码文件中手写的。
当然你可能也看到了右边的删除处理程序,但它只是将代码注释起来,并没有完全删除,没有强迫症的话,你用它也行。
但消息映射它似乎不会管,反正能手动删还是建议手动删除吧。
以上就是MFC的对话框的基本使用。
4.资源
前面提到了怎么在类向导中操作窗口,但我们并没有说过如何添加一个窗口。
一般我们的程序也不可能就一个窗口,那也太单调了,所以我们还得学会如何创建一个窗口。
而创建窗口在MFC里面也是非常的简单,就两步:
- 创建窗口资源
- 为窗口资源绑定一个类
首先我们来创建窗口资源,先来到资源视图,如果你没有看到资源视图,怎么找资源视图我应该就不用多说了吧?前面提到过。
我们可以看到这里有许多类型的资源,但这里我们只先看窗口资源,即Dialog
,右键Dialog
选择插入即可:
然后就生成了一个默认的窗口,其ID为资源视图中所示的:
首先就是改ID,不然以后窗口的ID全是一个名后面跟一串数字,那谁知道它是干嘛的对吧?
直接右键这个对话框资源点击属性(或者直接按F4
):
然后改就行了,但要注意别跟其它的ID重复:
自此,我们第一步就完成了,接下来是第二步,为这个窗口绑定类,方法很简单,就是右键这个窗口,添加类:
然后给这个类命名,最好符合MFC的命名规范,那就是类名前加C
,类名后加类型,这里是Dlg
。
还有就是基类,一般我们默认即可:
然后我们就可以看到生成了两个文件:
这两个文件与前面提到的Dlg
一样操作,因为他们都是CDialogEx
的子类嘛。
但一开始,他并没有初始化函数OnInitDialog
,怎么添加还记得吗?Ctrl+Ahift+X
打开类向导,选择该项目,该类,然后添加相应的虚函数即可,过程就不再赘述了。
此时我们就可以在主窗口中使用这个窗口,在主窗口类中添加这个窗口的头文件:
然后我们就可以在任意一个函数里面,实例化一个对象,然后调用DoModal
函数,比如我这里是在关闭函数里面调用的:
这时我们运行程序,点击关闭,就会发现,我们刚刚创建的窗口弹出来了,是不是用着很简单!
但这样用着有一个问题,那就是如果我们不关闭这个弹出的对话框,那么我们就没法点击它后面的对话框。
这种对话框叫做模态对话框,与之对应的叫做非模态对话框,使用方法如下。
我们直接定义一个新窗口的成员变量:
然后在初始化函数中创建它:
这里调用的Create
函数,传入的参数就是这个对话框资源的ID
,然后在我们想要使用的地方调用ShowWindow
函数即可:
其参数就是win APi的ShowWindow
的参数。
这里将后面的那段代码注释掉了,因为不注释的话,程序就直接结束了!
然后你就可以看到,此时两个窗口你都可以随意点击了。
5.控件
说完窗口,我们再来谈谈非常重要的一环,那就是控件。
因为我们几乎所有的应用程序,其目的就是为了接收用户的输入,然后我们进行输出的过程。
而对话框实际上只起到了一个容器的作用,因为几乎所有控件都是在对话框中的。
那什么是控件呢?其实很简单,前面我们用到的按钮就是一个控件。
所谓控件,其实就是官方写好的、具有特定功能的窗口给我们用,本质上来说,控件也是一种特殊的窗口。
那我们就来看看怎么使用控件,以及认识一些我们比较常用的控件。
5.1 按钮控件
首先打开想要添加控件的对话框资源,然后打开工具箱视图,找不到的,可以在 视图->工具箱 中找到:
然后我们就可以看到右边这些多种多样的控件,因为控件实在太多了,所以我这里只介绍几种非常常用的,其它控件后面章节会进行介绍。
首先,来看我们最常用的按钮控件,Button
这里注意一下,已经放在对话框上的控件,我们可以用鼠标选中它们,然后按Delete
键进行删除。
然后,我们就可以直接用鼠标左键,拖动旁边的控件到对话框中即可:
然后我们对这些控件基本就只有两个操作:
- 设置控件的属性。
- 响应控件的消息。
首先来看设置控件的属性,右键这个控件,然后点击属性即可:
对于按钮来说,我们最常用的就是下面两个属性:
描述文字是按钮上显示的文字,而ID
则是资源ID
,可自行设置。
还有最上方的动态布局:
意思是当你控件放在窗口内时,如果这个窗口的大小变化了,这个控件应该怎么变,就有大小与移动两种变化类型,可以自己试一下。
然后是外观:
故名思意,就是用来调整这个控件的样子的,这些只有自己试过才能印象深刻,都可以自己调一下,然后运行一下就知道了。
然后是行为:
这里注意一下,上面没讲,其实当你点击任意一个属性,最下面都有对应的描述,只是有点简短,可能依旧有点难懂,还是得自己试一试。
行为里面可能最常用的是接收文件与默认按钮。
所谓接收文件,就是用户可以直接拖文件到这个控件身上,但你得处理对应的消息。
比如一些软件有拖动文件进来就将其打开的功能,就是使用的这个。
然后默认按钮,就是当你窗口上有许多按钮时,这个按钮将作为你按Enter
键时,默认响应的按钮。
其它的基本就用不到,默认即可,需要了可以再自己研究一下。
上面说完属性,就来到第二步,响应消息,方法依旧很简单,直接右键控件,添加事件处理程序即可:
这里一定要注意选对类,因为它默认不是当前窗口的类,所以得自己选择这个控件所在的窗口类: