返回 1
第四章 利用 MFC开发 Windows应用程序本章导读理解 MFC的概念和作用 。
理解 Windows应用程序的特点和运行机制 。
掌握利用 MFC Appwizard 创建 Windows应用程序的步骤和方法,弄清 MFC Appwizard所创建的应用程序中所产生的主要类及其功能,组成文件和程序的框架结构 。
理解消息的概念,掌握编写 Windows应用程序过程中所涉及到的消息的种类,特点,消息的发送和接收的基本过程和机制 。
掌握消息映射,消息处理函数的概念及二者间的关系 。
掌握利用 Class Wizard增加、修改和删除窗口消息处理函数的方法和步骤,并理解程序代码的变化过程和特点。
返回 2
本章导读
MFC( Microsoft Foundation Class) 是 Microsoft公司推出的 Microsoft基本类库 。 在编写 Windows应用程序时,
必须编写的大量重复代码都由 MFC中定义的类和支持代码提供了;不必再直接使用 Windows API( 应用程序接口 ) 来进行编程工作,使用 MFC提供的位于 Windows
API之上的 C++库,使程序员的工作变得更加容易 。 在
Visual C++ 6.0中,用户不仅可以方便地使用 MFC,而且还可以使用向导 ( Wizard) 来辅助开发应用程序 。 MFC
实际上是一个扩展的,丰富的 C++类层次结构,在 MFC
中封装了 SDK结构,功能及应用程序框架内部技术,隐藏了过去许多 Windows程序不得不处理的许多重复工作 。
因此,从本章开始,将着重讨论如何利用 Visual C++ 6.0
的强大功能开发 Windows下的应用程序。
返回 3
4.1 Windows应用程序的特点与消息驱动机制基于 Windows操作系统的应用程序的特点是:
标准的图形用户界面,比如窗口,菜单,按钮,列表框等;
应用程序与硬件无关的特性,对于同一类硬件,不论厂家,型号,程序都无需进行任何修改就可以运行;
所有的 Windows应用程序都是消息驱动机制,也就是说 Windows程序是通过操作系统发送的消息来处理用户的输入的 。
在进行 Windows编程之前,必须了解 Windows的运行机制 。 在 Windows操作系统中,无论是系统产生的动作或是用户运行应用程序产生的动作都称为事件 (Events)产生的消息 (Message)。
无论是 Windows应用程序的设计、还是它的应用,都是基于消息驱动方式的,这是 Windows应用程序与传统的应返回 4
用程序最大的区别。在传统的编程方式中,程序是主动的。程序主动执行,只有当需要用户通过键盘或鼠标输入信息时,才进行查询或等待。获得输入后,程序继续运行。而 Windows应用程序是被动的,正常情况下,只是等待被消息触发。当用户点击鼠标或按下了键盘,则由操作系统将这些操作转化为特殊的消息,
传递给应用程序,应用程序再用对应的消息处理过程进行处理,处理完毕后,继续等待下一个消息。
消息驱动是 Windows操作系统的一大特色,操作系统将包括用户输入在内的各种事件以消息的形式发送到目标,目标系统再根据消息的具体内容进行相应的处理。
4.1 Windows应用程序的特点与消息驱动机制返回 5
4.2 利用 MFC Appwizard 创建 Windows应用程序在 C++中,事物之间的关系是通过类的派生和类的成员函数的重载来反映的 。 而在 Visual C++ 6.0中,类同样是最重要的元素 。 如一个字符串可以是类 Cstring的对象,
一个窗口可以是类 CWnd的对象,一个对话框可以是类
Cdialog的对象等等 。
Visual C++ 6.0中的 MFC AppWizard(应用程序向导 )可以使用户自动生成一些常用的标准程序结构和编程风格 。
例如一般的 Windows应用程序结构,DLL应用程序结构,
单文档 (SDI)应用程序结构,多文档 (MDI)应用程序结构等 。
下面详细介绍利用 MFC AppWizard创建一个 Windows
应用程序的步骤:
第零步 启动 Visual C++ 6.0,选择 【 File】 菜单下的 【 New】
菜单项,选择 【 Projects】 标签,选择 【 MFC
AppWizard(exe)】 项目类型,在 【 Project name】 中输入返回 6
项目名 MyExp,定位于,E:\C++\EXAMPLE\” 文件夹中,
单击 【 OK】 按钮 。
第一步 选择 【 Single document】 应用类型,即单文档应用程序,其他使用默认值,单击 【 Next】 按钮 。
第二步 让用户选择程序中是否加入数据库支持,在此使用默认值 【 None】,单击 【 Next】 按钮 。
第三步 让用户选择在程序中加入复合文档,自动化或
ActiveX控件的支持,在此使用默认值,单击 【 Next】 按钮 。
第四步 让用户选择应用程序的一些特性,在此使用默认值,
单击 【 Next】 按钮 。
第五步 让用户选择应用程序主窗口的风格,在源文件中是否加入注释,使用怎样的 MFC类库,在此使用默认值,单击 【 Next】 按钮 。
4.2 利用 MFC Appwizard 创建 Windows应用程序返回 7
第六步 用户可以对 MFC AppWizard提供的缺省类名,基类名,头文件名,源文件名进行修改,使用默认值,单击 【 Finish】 按钮 。 则会显示出用户在前面几个步骤中作出的选择内容,单击 【 OK】 按钮,系统开始创建应用程序,并回到 Visual C++ 6.0的主界面 。
运行过的应用程序 MyExp可以脱离 Visual C++ 6.0单独运行,运行该文档可以双击,E:\C++\EXAMPLE\Debug”
下的 MyExp.exe文件 。 和所有的 Windows应用程序一样,
MyExp也包含标题栏,菜单栏,工具栏,状态栏等窗口元素 。
4.2 利用 MFC Appwizard 创建 Windows应用程序返回 8
4.3 MFC应用程序的类和文件
4.3.1 类说明
AppWiZard在生成应用程序时,共派生了 5个类单击
,MyExp classes” 左侧的,+” 展开所有的类,即可显示出应用程序 MyExp的 5个类,其中:
CAboutDlg,关于 About对话框的对话框类
CMainFrame,主框架窗口类
CMyExpApp,应用程序类
CMyExpDoc,文档类
CMyExpView:视图类在工程中,每个类都拥有自己的类定义文件 ( *.H) 和类实现文件 ( *.CPP) 。 类定义文件主要保存各种类的定义;类实现文件主要保存各种类的成员函数的实现代码 。
返回 9
下面分别对这 5个类进行说明:
关于 About对话框的对话框类 CAboutDlg
CAboutDlg是工程 MyExp的对话框类,它是由 MFC类库中的 CDialog类派生而来的 。
主框架窗口类 CMainFrame
CMainFrame是工程 MyExp的主框架窗口类,它的基类是 CFrameWnd 。 头文件为 MainFrm.h,实现文件为
MainFrm.cpp。
主框架窗口类用于管理主程序的窗口,来显示窗口的标题栏,工具栏,状态栏等;同时还处理对窗口操作的消息,例如窗口最大化,最小化,改变窗口大小等一般操作 。 视图窗口是主框架窗口的子集,对于多文档界面
( MDI) 应用程序,主框架窗口是所有 MDI子窗口的容器 。
4.3 MFC应用程序的类和文件返回 10
应用程序类 CMyExpApp
CMyExpApp是工程 MyExp的应用程序类,它的基类是
CWinApp。 头文件为 MyExp,h,实现文件为 MyExp.cpp。
应用程序类管理程序的整体,控制应用程序的所有对象,包括文档,视图和边框窗口,并完成应用程序的初始化工作和程序退出时的清除工作 。
注意:每个基于 MFC的应用程序都必须有一个从
CWinApp类派生的对象 。
文档类 CMyExpDoc
CMyExpDoc 是工程 MyExp 的文档类,它的基类是
CDocument 。 头 文 件 为 MyExpDoc.h,实 现 文 件 为
MyExpDoc.cpp。
4.3 MFC应用程序的类和文件返回 11
文档类负责存放程序的数据并读取磁盘文件数据,或将磁盘文件数据写入磁盘文件中 。 文档类必须通过视图类实现与用户的交互 。
视图类 CMyExpView
CMyExpView是工程 MyExp的视图类,它的基类是
CView 。 头文件为 MyExpView.h,实现文件为
MyExpView.cpp。
视图类主要负责管理视图窗口,显示文档类中的数据,
可以显示在屏幕上,也可以输出到打印机或其他设备上;
也负责处理用户数据,接受用户对数据的鼠标、键盘操作并传送给文档类对象。
4.3 MFC应用程序的类和文件返回 12
4.3 MFC应用程序的类和文件
4.3.2 文件说明
App Wizard在自动生成工程时,除了生成上面介绍的各个类的头文件和实现文件外,还生成了一些为建立应用程序所需要的其他文件。这些文件可以在应用程序生成时指定的路径( E:\C++\EXAMPLE\MyExp)中找到,
下面分别对这些文件加以说明:
1,MyExp.clw,Class Wizard的信息存储文件,存储由
Class Wizard编辑已有的类或添加新类的信息,存储由
Class Wizard建立和编辑各种消息处理函数和映射变量等的信息 。
2,MyExp.dsp,Project文件,即工程文件 。 Project文件中保存着工程的各种信息,一个工程文件对应一个工程应用程序 。
返回 13
3,MyExp.dsw,Workspace文件 。 一个 Workspace文件可包含一个或多个工程 。
4,MyExp.rc:资源定义文件,包含程序资源的定义,其中保存了应用程序中使用到的各种资源的信息,包括存贮在文件夹中的图标,位图和光标等 。
5,Resource.h:标准的头文件,它包含了所有资源符号的定义,与 MyExp.rc文件相对应 。
6,StdAfx.h:包含在所有 App Wizard程序中的标准头文件,
它用于包含其他包含在预编译头文件中文件 。
7,StdAfx.cpp:包含在所有 App Wizard程序中,它包含所有标准 include文件 。
8,res\MyExpDoc.ico:文件中包含了打开文档时所用的图标文件 。
4.3 MFC应用程序的类和文件返回 14
9,res\MyExp.rc2:资源定义文件,包含了用 vc不能直接编辑的资源 。 可以将所有不能由资源编辑器编辑的资源放置到这个文件中 。
10,res\MyExp.ico:应用程序的图标文件 。 应用程序图标包含在资源文件 MyExp.rc中 。
11,res\Toolbar.bmp:用于创建工具栏按钮的位图文件 。
初始栏工具栏和状态栏是在主边框窗口类中构造的 。
12,ReadMe.txt:包含了对所有该程序的文件的解释信息,
并说明了所有创建的类 。
另外,如 果 在 App Wizard 的第 4 步 中 选 择 了
Context_sensitive Help选项,则 App Wizard会自动生成一个,hpj文件和一些,rtf文件,它们用以给出上下文的帮助 。
4.3 MFC应用程序的类和文件返回 15
Windows 应用程序一般是由消息驱动的 ( message-
driven),这也是 Windows编程方式与其他编程方式最大的不同之处 。
消息就是操作系统通知应用程序某件事情已经发生的一种方式 。 例如,当用户移动或双击鼠标,改变窗口大小等,都将向适当的窗口发送消息,一个窗口可以向另一个窗口发送消息,并且大多数窗口通过向其他窗口发送一个稍有不同的消息来响应消息 。
Windows系统中的消息主要有三种类型:标准的
Windows消息,控件消息和命令消息 。
4.4 Windows消息返回 16
4.4 Windows消息
4.4.1 标准的 Windows消息所有以 WM_为前缀的消息都是标准的 Windows消息
( WM_COMMAND 消息除外 ),如 WM_PAINT,
WM_QUIT等,这些消息通常含有用于确定如何对消息进行处理的一些参数 。 标准的 Windows 消息一般由窗口对象和视图对象进行处理 。 窗口对象指的是从 CWnd中派生出的类的对象,如从 CWnd,CFrameWnd,
CMDIFrameWnd,CMDIChildWnd,Cview,Cdialog等
MFC类或这些类的派生类定义的对象 ( 这些类都是
CWnd类直接或间接派生的 ) 。
返回 17
4.4 Windows消息标准的 Windows消息可以分为三类,即键盘消息,鼠标消息和窗口消息 。 下面分别加以说明 。
键盘消息当键盘的某个键被按下时,将产生 WM_CHAR消息,
这个消息带有字符代码值,重复次数和先前状态码三个参数 。 WM_CHAR消息的处理函数为 OnChar( ),此函数的原型为:
afx_msg void Onchar(UINT nChar,UINT nRepCnt,UINT nFlags);
其中,nChar是所按键的字符代码值;
nRepCnt是重复的次数,它表示用户按键时重复击键的次数;
nFlags表示扫描码,先前键状态和键转换状态等,其参数值功能描述见表 4.1所示 。
返回 18
4.4 Windows消息位 含 义
0~ 15 指明键重复按下的次数
16~ 23 指定扫描码,依赖于具体厂家的按键值
24 如果同时按下扩展键 ( 如功能键 Alt,Ctrl),则置为 1,否则置为 0
25~ 28 由 Windows内部使用
29 若同时按下了 Alt键,则置为 1,否则置为 0
30 指明先前键状态 。 若消息发出前键是按下的,则置为 1,否则置为 0
31 指明键转换状态 。 若按键已松开,则置为 1,否则置为 0
表 4.1 nFlags参数值功能描述返回 19
4.4 Windows消息鼠标消息在 Windows中处理鼠标的操作基本上有三种:
1,单击 (Click) 2,双击 ( Double Click) 3.拖动 ( Drag)
所有这些鼠标的操作,都会产生相应的消息 。 鼠标移动时产生 WM_MOUSEMOVE消息,鼠标左键按下时产生
WM_LBUTTONDOWN 消息,鼠 标 右 键 按 下 时 产 生
WM_RBUTTONDOWN 消息,鼠 标 左 键 双 击 时 产 生
WM_LBOTTONDBLCLK消息等等 。
所有这些鼠标消息的处理函数都有相似的原型,它们都有两个参数。我们以处理鼠标左键按下的消息函数
OnLButtonDown( )为例来进行说明。此函数的原型如下:
afx_msg void OnLButtonDown(UINT nFlags,Cpoint point);
其中:参数 point是鼠标事件发生时鼠标光标所在的位置,
它是相对于窗口左上角的水平坐标和垂直坐标而言的 。
返回 20
4.4 Windows消息参数 nFlag指明鼠标按钮的状态以及鼠标事件发生时键盘上某些键的状态,每一状态都可以由 nFlag的一位来表示。我们可以从表 4.2中所列的位屏蔽中得到每一位。
4.2 nFlags参数每位的含义其中,MK_CONTROL,MK_LBUTTON,MK_MBUTTON、
MK_MBUTTON,MK_RBUTTON和 MK_SHIFT都是预定义的宏。
位屏蔽 含 义
MK_CONTROL Ctrl键按下时设置
MK_LBUTTON 鼠标左键按下时设置
MK_MBUTTON 鼠标中间键按下时设置
MK_RBUTTON 鼠标右键按下时设置
MK_SHIFT Shift键按下时设置返回 21
4.4 Windows消息窗口消息所有窗口的变化,包括窗口内容重绘 WM_PAINT,窗口最大化 WM_MAXIMIZE,窗口最小化 WM_MINIMIZE、
窗口重定义大小 WM_RESIZE,窗口滚动 WM_HSCROLL、
WM_VSCROLL,窗口定时 WM_TIMER等消息所带参数各不相同 。
在这里我们来详细讨论一下 WM_PAINT消息 。 当调用成员函数 UpdateWindow( )或 RedrawWindow( )要求重新绘制窗口内容时,应用程序将收到 WM_PAINT消息 。 当窗口最小化后再还原或被其他窗口遮盖后又重新显示时,
则当前窗口中的内容必须重新绘制,消息 WM_PAINT就是为实现这个功能的 。
返回 22
4.4 Windows消息当向 Windows应用程序发送 WM_PAINT消息,应用程序检索到此消息后,就重新显示窗口中的内容 。 WM_PAINT消息的处理函数为 OnPaint( )。
函数原型为:
afx_msg void OnPaint( );
如果想详细了解所有的标准的 Windows消息,可以参阅
Visual C++ 6.0联机帮助中的有关内容 。
4.4.2 控件消息控件是一个小的子窗口,属于其他窗口 ( 如对话框等 ),
能够接受操作并象父窗口发送消息 。 常见的控件有按钮,
列表框,编辑框,复合框,滚动条等 。
在 Visual C++ 6.0中,对控件的操作都是通过生成相应的控件类来进行 。 这些控件类仅能发送少量特定的消息,这些消息就叫做控件消息 。 发送控件消息的控件在 Visual C++中返回 23
4.4 Windows消息使用唯一 ID号来进行标识,使用控件类来操纵。
控件消息分为两类:
1,从控件传给消息,通常这类消息的前缀的最后一个字符为 N;
2,由系统发送给控件的消息,这类消息的前缀的最后一个字符为 M。
例如,当用户对编辑框中的文本进行修改时,编辑框将发送给父窗口一条包含控件通知码 EN_CHANGE 的
WM_COMMAND消息 。 窗口的消息处理函数将以某种适当的方式对通知消息作出响应,如检索编辑框中的文本 。
与其他标准的 Windows消息一样,控件消息也是由窗口对象和视图对象进行处理 。
返回 24
4.4 Windows消息
4.4.3 命令消息命令消息主要包括由用户界面对象发送的 M_COMMAND
消息,用户界面对象是指菜单、工具栏、快捷键等。它和控件消息的区别在于:控件消息只能由特定控件向
Windows系统传送,而命令消息是由用户界面发送的,它可以被更多的对象处理。在文档对象、视图对象、窗体对象、控件对象中都能处理这种消息。
1,用户界面对象菜单、工具栏、快捷键等都是可以产生命令的用户界面对象。每个这样的对象都分配了一个 ID号,通过给对象和命令分配同一个 ID号,将用户界面对象和命令联系在一起。例如,选择程序中的 【 文件 】 菜单下的 【 打开 】
菜单项,则产生一条 ID_FILE_OPEN命令,然后通过消息映射调用函数 OnFileOpen()来进行处理。
返回 25
4.4 Windows消息
2,命令 ID
在 MFC编程中,命令完全由命令 ID来进行描述,命令 ID
分配给产生此命令的用户界面对象。通常情况下,命令 ID
是由它所表示的用户界面对象的功能来命名的。 MFC预定义了一些命令 ID,如 ID_EDIT_CUT,ID_FILE_SAVE 等,
而其他命令 ID则要由编程人员自己定义。
3,命令目标当用户界面对象被单击后,将调用处理函数来执行所产生的命令。 Windows把非命令消息的消息直接发送给窗口,
窗口中用于处理这些消息的处理函数将被调用。而对于命令消息,将把命令发送给多个目标,也就是命令目标,其中通常有一个要调用此命令的处理函数。
返回 26
4.5 消息的发送和接收的基本过程和机制在 Windows中,大部分的消息都是由用户和应用程序的相互作用而产生的 。 CWinApp类的成员函数 Run( )用于处理消息循环,它唯一的功能就是等待消息,并将消息发送到适当的窗口 。
当消息循环接收到一条 Windows消息时,它首先通过查询一种内部结构来确定消息要发送的窗口 。 这种内部结构把当前所有的窗口映像成其对应的窗口类 。 MFC的基类还能够检测这一目标类是否在其消息中为这一消息提供了处理函数入口 。 如果找到入口,则消息被送往处理函数,结束消息发送过程 。 如果消息无对应入口,则对目标类进行基类消息映射检测,沿着层次向上查找,
直到找到入口函数为止 。
对于命令消息来说,查找较为复杂。通常,每个命令目标类先把命令发送给某些其他的对象,使其他对象有返回 27
4.5 消息的发送和接收的基本过程和机制优先处理的机会。如果这些对象都不能处理此命令,则起始类检查自己的消息映射,若也不能处理此消息,则将命令发送给更多的命令目标。
在大多数情况下,命令目标将以下列顺序发送命令:
1,发送至当前活动的子命令目标对象;
2,发送至其本身;
3,发送至其他命令目标 。
【 例 】 在一个 MDI应用程序中,如果选择了,文件,菜单中的,保存,菜单项,则产生一条命令消息 。 我们假定命令处理函数是应用程序文档类的成员函数,则此命令的发送顺序为:
返回 28
4.5 消息的发送和接收的基本过程和机制
1,命令消息首先传给主框架窗口;
2,主框架窗口给当前活动的子窗口处理此命令的机会;
3,视图检查其消息映射,若没有找到处理函数,再把此命令发送给与其相连的文档;
4,文档检查其消息映射,如果找到命令的处理函数,则调用此函数,发送过程结束,否则继续下面的步骤;
5,将命令发送给文档模板,然后返回到视图,再返回边框窗口,边框窗口检查其消息映射;
6,命令回送到主边框窗口,主边框窗口检查自己的消息映射;
7,检测应用程序的消息映射,进到消息入口,并调用适当的处理程序。
返回 29
4.6 消息映射与消息处理函数
4.6.1 消息映射与消息处理函数的概念通过消息映射,消息就和它的处理函数对应起来 。
消息处理函数指的是与某个消息对应的函数 。 消息处理函数的执行是由其对应的消息引发的,某个类对象中的消息处理函数是与这个类对象能够得到的一个消息对应的,当这个消息发生时,这个函数就会被执行 。
消息处理函数的定义与使用方法与类的一般的成员函数不同。一般成员函数包括两部分:函数的定义部分和函数的实现部分;而消息处理函数除了这两部分以外,
还有消息映射部分。
返回 30
4.6 消息映射与消息处理函数
4.6.2 管理窗口消息处理函数利用 Class Wizard可以管理消息处理函数,Class Wizard
是一个非常强大有用的工具,我们可以用 Class Wizard来创建新类,定义消息处理函数,覆盖 MFC的虚拟函数,
从对话框,表单视图或记录视图的控件中获取数据 。
可以用三种方法来激活 Class Wizard对话框:
1,选择 【 View】 菜单中的 【 Class Wizard】 菜单项;
2,直接按下 Ctrl+W键;
3,在代码编辑窗口中单击鼠标右键 ( 此时,代码编辑窗口中必须有打开的文件 ),在弹出菜单中选择 【 Class
Wizard】 菜单项 。
返回 31
4.6 消息映射与消息处理函数当执行了以上操作,窗口中将弹出 【 MFC Class Wizard】
对话框。此时显示的是 【 Message Map】 选项卡。在这个选项卡的最上面有两个下拉列表框,【 Project】 列表中显示的是当前的项目名称,【 Class name】 列表中显示的是正在编辑的消息映射所属的类名。选项卡的中间也有两个多行的列表框。左边的 【 Object IDs】 列表框中显示的对象有三种类型:在 【 Class name】 栏中列出的类名、菜单项对象和其他可能在 【 Class name】 中所选的类传递消息的控件,当其中的某一个类被选中时,右面的 【 Messages 】
列表框就显示出此类的能捕获的所有 Windows消息。其中还列出了一些能够捕获的普通消息的虚函数。最下面
【 Member functions】 列表中显示的是与此消息相关的类的成员函数的列表。
返回 32
4.6 消息映射与消息处理函数在 【 MFC Class Wizard】 对话框中共有五个选项卡,分别说明如下:
1,【 Message Maps】 选项卡 用于进行消息映射的处理;
2,【 Member Variables】 选项卡 用于为对话框中的控件所用到的类创建成员变量;
3,【 Automation】 选项卡 帮助用户管理与 OLE自动化相联系的方法和属性;
4,【 ActiveX Events】 选项卡 帮助用户管理 ActiveX类支持的 ActiveX事件;
5,【 Class Info】 选项卡 显示类的一般信息,包括定义它的头文件和源文件,类名以及与之相联系的基类 。
返回 33
4.6 消息映射与消息处理函数
4.6.2.1 增加一个窗口消息以应用程序 MyExp为例,说明用 Class Wizard增加一个窗口消息处理函数的过程 。
1.在 VC++工作界面下打开 MyExp项目,并启动 Class
Wizard,进入对话框界面 。
2,从 【 Class Name】 复合框中选择视图类 CMyExpView,在
【 Object IDs】 列表框中就会列出各种消息来源的组件 。
3,从 【 Object IDs】 列表框中选择 CMyExpView,在列表框 【 Message】 中列出的就是 CMyExpView 类对象能够从窗口对象 CWnd接受到的窗口消息和各种可重载的虚函数 。
从中可以找到名为 WM_LBUTTONDOWN 的消息,用鼠标选中这个消息 。
返回 34
4.6 消息映射与消息处理函数
4,此时,【 Add Function】 按钮处于可执行状态,单击此按钮,就会在 CMyExpView类中增加一个被 CWnd保护的消息处理函数 OnLButtonDown。
5,在 【 Member functions】 列表框中能够发现这个函数及其对应的消息映射机制,O n L B u t t o n D o w n
ON_WM_LBUTTONDOWN。 在函数前有一个,W,标志,表示这个函数是一个窗口消息处理函数 。
6,单击 【 OK】 按钮,完成一个窗口消息处理函数的增加。
4.6.2.2 增加窗口消息处理函数的过程的分析以上介绍了用 Class Wizard增加一个窗口消息处理函数的过程,增加了该函数后,对于应用程序 MyExp
的代码做了如下的修改:
返回 35
4.6 消息映射与消息处理函数
1,在视图类 CMyExpView中,增加了消息处理函数的定义代码:
//省略以上代码
protected:
//{{AFX_MSG(CMyExpView)
afx_msg void OnLButtonDown(UINT nFlags,CPoint
point); //单击鼠标左键调用
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
//省略以下代码返回 36
4.6 消息映射与消息处理函数
2,在 CMyExpView 类的实现文件 MyExpview.cpp中,增加了函数的实际代码:
void CMyExpView::OnLButtonDown(UINT nFlags,CPoint point)
{
//TODO,Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags,point);
}
3,在实现文件 MyExpView.cpp中,还增加了函数的消息映射机制:
BEGIN_MESSAGE_MAP(CMyExpView,CView)
//{{AFX_MSG_MAP(CMyExpView)
返回 37
4.6 消息映射与消息处理函数
ON_WM_LBUTTONDOWN() //单击鼠标左键,
//OnLButtonDown 函数的消息映射
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT,CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT,view::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW,
CView::OnFilePrintPreview)
END_MESSAGE_MAP()
返回 38
4.6 消息映射与消息处理函数
4.6.2.3 Class Wizard 识别和处理窗口消息处理函数所需要的标识
1,窗口消息处理函数的定义在类的定义文件中,Class Wizard通过以下两行固定的代码来标识消息处理函数:
//{{AFX_MSG(CMyExpView) //Class Wizard标识消息
//处理函数定义的起始代码
//}}AFX_MSG //Class Wizard标识消息处理函数定义
// 的结束代码
AFX_MSG括号中的内容 (CMyExpView)是消息处理函数所在类的名称,只有将消息处理函数定义在以上两行代码间时,才能被 Class Wizard识别和处理 。
返回 39
4.6 消息映射与消息处理函数
2,窗口消息处理函数的实现在实现文件中,消息映射机制写在如下的两行代码间而被 ClassWizard识别:
//{{AFX_MSG_MAP(CMyExpView) //Class Wizard标识消
//息处理映射机制的起始代码
//}}AFX_MSG_MAP //Class Wizard标识消息处理
//映射机制的结束代码同样,AFX_MSG_MAP括号中的内容是拥用消息映射机制的类的名称,只有当一个消息处理函数的消息映射机制写在以上两行代码间时,才能被 Class Wizard 识别和处理 。
返回 40
4.6 消息映射与消息处理函数
4.6.2.4 删除窗口消息处理函数用 Class Wizard 删除窗口消息处理函数的方法很简单:
在操作界面中,从 【 Member Functions】 列表框中选择刚刚增加的 OnLButtonDown函数,这时 【 Delete Funtion】
按钮处于激活可执状态,单击此按钮,系统会提示是否对 OnLButtonDown函数进行删除,并提示必须用手工从实现文件中删除函数的实际代码,确认后就删除了这个消息处理函数 。
以上操作只是从视图类 CMyExpView 中删除了函数的定义代码,从实现文件中删除了映射消息机制,而对于实现文件中的函数实现代码,需要手工进行删除 。 这样做的目的是避免误操作而删除大量有用的代码 。
返回 41
本章小结返回 42
习题
第四章 利用 MFC开发 Windows应用程序本章导读理解 MFC的概念和作用 。
理解 Windows应用程序的特点和运行机制 。
掌握利用 MFC Appwizard 创建 Windows应用程序的步骤和方法,弄清 MFC Appwizard所创建的应用程序中所产生的主要类及其功能,组成文件和程序的框架结构 。
理解消息的概念,掌握编写 Windows应用程序过程中所涉及到的消息的种类,特点,消息的发送和接收的基本过程和机制 。
掌握消息映射,消息处理函数的概念及二者间的关系 。
掌握利用 Class Wizard增加、修改和删除窗口消息处理函数的方法和步骤,并理解程序代码的变化过程和特点。
返回 2
本章导读
MFC( Microsoft Foundation Class) 是 Microsoft公司推出的 Microsoft基本类库 。 在编写 Windows应用程序时,
必须编写的大量重复代码都由 MFC中定义的类和支持代码提供了;不必再直接使用 Windows API( 应用程序接口 ) 来进行编程工作,使用 MFC提供的位于 Windows
API之上的 C++库,使程序员的工作变得更加容易 。 在
Visual C++ 6.0中,用户不仅可以方便地使用 MFC,而且还可以使用向导 ( Wizard) 来辅助开发应用程序 。 MFC
实际上是一个扩展的,丰富的 C++类层次结构,在 MFC
中封装了 SDK结构,功能及应用程序框架内部技术,隐藏了过去许多 Windows程序不得不处理的许多重复工作 。
因此,从本章开始,将着重讨论如何利用 Visual C++ 6.0
的强大功能开发 Windows下的应用程序。
返回 3
4.1 Windows应用程序的特点与消息驱动机制基于 Windows操作系统的应用程序的特点是:
标准的图形用户界面,比如窗口,菜单,按钮,列表框等;
应用程序与硬件无关的特性,对于同一类硬件,不论厂家,型号,程序都无需进行任何修改就可以运行;
所有的 Windows应用程序都是消息驱动机制,也就是说 Windows程序是通过操作系统发送的消息来处理用户的输入的 。
在进行 Windows编程之前,必须了解 Windows的运行机制 。 在 Windows操作系统中,无论是系统产生的动作或是用户运行应用程序产生的动作都称为事件 (Events)产生的消息 (Message)。
无论是 Windows应用程序的设计、还是它的应用,都是基于消息驱动方式的,这是 Windows应用程序与传统的应返回 4
用程序最大的区别。在传统的编程方式中,程序是主动的。程序主动执行,只有当需要用户通过键盘或鼠标输入信息时,才进行查询或等待。获得输入后,程序继续运行。而 Windows应用程序是被动的,正常情况下,只是等待被消息触发。当用户点击鼠标或按下了键盘,则由操作系统将这些操作转化为特殊的消息,
传递给应用程序,应用程序再用对应的消息处理过程进行处理,处理完毕后,继续等待下一个消息。
消息驱动是 Windows操作系统的一大特色,操作系统将包括用户输入在内的各种事件以消息的形式发送到目标,目标系统再根据消息的具体内容进行相应的处理。
4.1 Windows应用程序的特点与消息驱动机制返回 5
4.2 利用 MFC Appwizard 创建 Windows应用程序在 C++中,事物之间的关系是通过类的派生和类的成员函数的重载来反映的 。 而在 Visual C++ 6.0中,类同样是最重要的元素 。 如一个字符串可以是类 Cstring的对象,
一个窗口可以是类 CWnd的对象,一个对话框可以是类
Cdialog的对象等等 。
Visual C++ 6.0中的 MFC AppWizard(应用程序向导 )可以使用户自动生成一些常用的标准程序结构和编程风格 。
例如一般的 Windows应用程序结构,DLL应用程序结构,
单文档 (SDI)应用程序结构,多文档 (MDI)应用程序结构等 。
下面详细介绍利用 MFC AppWizard创建一个 Windows
应用程序的步骤:
第零步 启动 Visual C++ 6.0,选择 【 File】 菜单下的 【 New】
菜单项,选择 【 Projects】 标签,选择 【 MFC
AppWizard(exe)】 项目类型,在 【 Project name】 中输入返回 6
项目名 MyExp,定位于,E:\C++\EXAMPLE\” 文件夹中,
单击 【 OK】 按钮 。
第一步 选择 【 Single document】 应用类型,即单文档应用程序,其他使用默认值,单击 【 Next】 按钮 。
第二步 让用户选择程序中是否加入数据库支持,在此使用默认值 【 None】,单击 【 Next】 按钮 。
第三步 让用户选择在程序中加入复合文档,自动化或
ActiveX控件的支持,在此使用默认值,单击 【 Next】 按钮 。
第四步 让用户选择应用程序的一些特性,在此使用默认值,
单击 【 Next】 按钮 。
第五步 让用户选择应用程序主窗口的风格,在源文件中是否加入注释,使用怎样的 MFC类库,在此使用默认值,单击 【 Next】 按钮 。
4.2 利用 MFC Appwizard 创建 Windows应用程序返回 7
第六步 用户可以对 MFC AppWizard提供的缺省类名,基类名,头文件名,源文件名进行修改,使用默认值,单击 【 Finish】 按钮 。 则会显示出用户在前面几个步骤中作出的选择内容,单击 【 OK】 按钮,系统开始创建应用程序,并回到 Visual C++ 6.0的主界面 。
运行过的应用程序 MyExp可以脱离 Visual C++ 6.0单独运行,运行该文档可以双击,E:\C++\EXAMPLE\Debug”
下的 MyExp.exe文件 。 和所有的 Windows应用程序一样,
MyExp也包含标题栏,菜单栏,工具栏,状态栏等窗口元素 。
4.2 利用 MFC Appwizard 创建 Windows应用程序返回 8
4.3 MFC应用程序的类和文件
4.3.1 类说明
AppWiZard在生成应用程序时,共派生了 5个类单击
,MyExp classes” 左侧的,+” 展开所有的类,即可显示出应用程序 MyExp的 5个类,其中:
CAboutDlg,关于 About对话框的对话框类
CMainFrame,主框架窗口类
CMyExpApp,应用程序类
CMyExpDoc,文档类
CMyExpView:视图类在工程中,每个类都拥有自己的类定义文件 ( *.H) 和类实现文件 ( *.CPP) 。 类定义文件主要保存各种类的定义;类实现文件主要保存各种类的成员函数的实现代码 。
返回 9
下面分别对这 5个类进行说明:
关于 About对话框的对话框类 CAboutDlg
CAboutDlg是工程 MyExp的对话框类,它是由 MFC类库中的 CDialog类派生而来的 。
主框架窗口类 CMainFrame
CMainFrame是工程 MyExp的主框架窗口类,它的基类是 CFrameWnd 。 头文件为 MainFrm.h,实现文件为
MainFrm.cpp。
主框架窗口类用于管理主程序的窗口,来显示窗口的标题栏,工具栏,状态栏等;同时还处理对窗口操作的消息,例如窗口最大化,最小化,改变窗口大小等一般操作 。 视图窗口是主框架窗口的子集,对于多文档界面
( MDI) 应用程序,主框架窗口是所有 MDI子窗口的容器 。
4.3 MFC应用程序的类和文件返回 10
应用程序类 CMyExpApp
CMyExpApp是工程 MyExp的应用程序类,它的基类是
CWinApp。 头文件为 MyExp,h,实现文件为 MyExp.cpp。
应用程序类管理程序的整体,控制应用程序的所有对象,包括文档,视图和边框窗口,并完成应用程序的初始化工作和程序退出时的清除工作 。
注意:每个基于 MFC的应用程序都必须有一个从
CWinApp类派生的对象 。
文档类 CMyExpDoc
CMyExpDoc 是工程 MyExp 的文档类,它的基类是
CDocument 。 头 文 件 为 MyExpDoc.h,实 现 文 件 为
MyExpDoc.cpp。
4.3 MFC应用程序的类和文件返回 11
文档类负责存放程序的数据并读取磁盘文件数据,或将磁盘文件数据写入磁盘文件中 。 文档类必须通过视图类实现与用户的交互 。
视图类 CMyExpView
CMyExpView是工程 MyExp的视图类,它的基类是
CView 。 头文件为 MyExpView.h,实现文件为
MyExpView.cpp。
视图类主要负责管理视图窗口,显示文档类中的数据,
可以显示在屏幕上,也可以输出到打印机或其他设备上;
也负责处理用户数据,接受用户对数据的鼠标、键盘操作并传送给文档类对象。
4.3 MFC应用程序的类和文件返回 12
4.3 MFC应用程序的类和文件
4.3.2 文件说明
App Wizard在自动生成工程时,除了生成上面介绍的各个类的头文件和实现文件外,还生成了一些为建立应用程序所需要的其他文件。这些文件可以在应用程序生成时指定的路径( E:\C++\EXAMPLE\MyExp)中找到,
下面分别对这些文件加以说明:
1,MyExp.clw,Class Wizard的信息存储文件,存储由
Class Wizard编辑已有的类或添加新类的信息,存储由
Class Wizard建立和编辑各种消息处理函数和映射变量等的信息 。
2,MyExp.dsp,Project文件,即工程文件 。 Project文件中保存着工程的各种信息,一个工程文件对应一个工程应用程序 。
返回 13
3,MyExp.dsw,Workspace文件 。 一个 Workspace文件可包含一个或多个工程 。
4,MyExp.rc:资源定义文件,包含程序资源的定义,其中保存了应用程序中使用到的各种资源的信息,包括存贮在文件夹中的图标,位图和光标等 。
5,Resource.h:标准的头文件,它包含了所有资源符号的定义,与 MyExp.rc文件相对应 。
6,StdAfx.h:包含在所有 App Wizard程序中的标准头文件,
它用于包含其他包含在预编译头文件中文件 。
7,StdAfx.cpp:包含在所有 App Wizard程序中,它包含所有标准 include文件 。
8,res\MyExpDoc.ico:文件中包含了打开文档时所用的图标文件 。
4.3 MFC应用程序的类和文件返回 14
9,res\MyExp.rc2:资源定义文件,包含了用 vc不能直接编辑的资源 。 可以将所有不能由资源编辑器编辑的资源放置到这个文件中 。
10,res\MyExp.ico:应用程序的图标文件 。 应用程序图标包含在资源文件 MyExp.rc中 。
11,res\Toolbar.bmp:用于创建工具栏按钮的位图文件 。
初始栏工具栏和状态栏是在主边框窗口类中构造的 。
12,ReadMe.txt:包含了对所有该程序的文件的解释信息,
并说明了所有创建的类 。
另外,如 果 在 App Wizard 的第 4 步 中 选 择 了
Context_sensitive Help选项,则 App Wizard会自动生成一个,hpj文件和一些,rtf文件,它们用以给出上下文的帮助 。
4.3 MFC应用程序的类和文件返回 15
Windows 应用程序一般是由消息驱动的 ( message-
driven),这也是 Windows编程方式与其他编程方式最大的不同之处 。
消息就是操作系统通知应用程序某件事情已经发生的一种方式 。 例如,当用户移动或双击鼠标,改变窗口大小等,都将向适当的窗口发送消息,一个窗口可以向另一个窗口发送消息,并且大多数窗口通过向其他窗口发送一个稍有不同的消息来响应消息 。
Windows系统中的消息主要有三种类型:标准的
Windows消息,控件消息和命令消息 。
4.4 Windows消息返回 16
4.4 Windows消息
4.4.1 标准的 Windows消息所有以 WM_为前缀的消息都是标准的 Windows消息
( WM_COMMAND 消息除外 ),如 WM_PAINT,
WM_QUIT等,这些消息通常含有用于确定如何对消息进行处理的一些参数 。 标准的 Windows 消息一般由窗口对象和视图对象进行处理 。 窗口对象指的是从 CWnd中派生出的类的对象,如从 CWnd,CFrameWnd,
CMDIFrameWnd,CMDIChildWnd,Cview,Cdialog等
MFC类或这些类的派生类定义的对象 ( 这些类都是
CWnd类直接或间接派生的 ) 。
返回 17
4.4 Windows消息标准的 Windows消息可以分为三类,即键盘消息,鼠标消息和窗口消息 。 下面分别加以说明 。
键盘消息当键盘的某个键被按下时,将产生 WM_CHAR消息,
这个消息带有字符代码值,重复次数和先前状态码三个参数 。 WM_CHAR消息的处理函数为 OnChar( ),此函数的原型为:
afx_msg void Onchar(UINT nChar,UINT nRepCnt,UINT nFlags);
其中,nChar是所按键的字符代码值;
nRepCnt是重复的次数,它表示用户按键时重复击键的次数;
nFlags表示扫描码,先前键状态和键转换状态等,其参数值功能描述见表 4.1所示 。
返回 18
4.4 Windows消息位 含 义
0~ 15 指明键重复按下的次数
16~ 23 指定扫描码,依赖于具体厂家的按键值
24 如果同时按下扩展键 ( 如功能键 Alt,Ctrl),则置为 1,否则置为 0
25~ 28 由 Windows内部使用
29 若同时按下了 Alt键,则置为 1,否则置为 0
30 指明先前键状态 。 若消息发出前键是按下的,则置为 1,否则置为 0
31 指明键转换状态 。 若按键已松开,则置为 1,否则置为 0
表 4.1 nFlags参数值功能描述返回 19
4.4 Windows消息鼠标消息在 Windows中处理鼠标的操作基本上有三种:
1,单击 (Click) 2,双击 ( Double Click) 3.拖动 ( Drag)
所有这些鼠标的操作,都会产生相应的消息 。 鼠标移动时产生 WM_MOUSEMOVE消息,鼠标左键按下时产生
WM_LBUTTONDOWN 消息,鼠 标 右 键 按 下 时 产 生
WM_RBUTTONDOWN 消息,鼠 标 左 键 双 击 时 产 生
WM_LBOTTONDBLCLK消息等等 。
所有这些鼠标消息的处理函数都有相似的原型,它们都有两个参数。我们以处理鼠标左键按下的消息函数
OnLButtonDown( )为例来进行说明。此函数的原型如下:
afx_msg void OnLButtonDown(UINT nFlags,Cpoint point);
其中:参数 point是鼠标事件发生时鼠标光标所在的位置,
它是相对于窗口左上角的水平坐标和垂直坐标而言的 。
返回 20
4.4 Windows消息参数 nFlag指明鼠标按钮的状态以及鼠标事件发生时键盘上某些键的状态,每一状态都可以由 nFlag的一位来表示。我们可以从表 4.2中所列的位屏蔽中得到每一位。
4.2 nFlags参数每位的含义其中,MK_CONTROL,MK_LBUTTON,MK_MBUTTON、
MK_MBUTTON,MK_RBUTTON和 MK_SHIFT都是预定义的宏。
位屏蔽 含 义
MK_CONTROL Ctrl键按下时设置
MK_LBUTTON 鼠标左键按下时设置
MK_MBUTTON 鼠标中间键按下时设置
MK_RBUTTON 鼠标右键按下时设置
MK_SHIFT Shift键按下时设置返回 21
4.4 Windows消息窗口消息所有窗口的变化,包括窗口内容重绘 WM_PAINT,窗口最大化 WM_MAXIMIZE,窗口最小化 WM_MINIMIZE、
窗口重定义大小 WM_RESIZE,窗口滚动 WM_HSCROLL、
WM_VSCROLL,窗口定时 WM_TIMER等消息所带参数各不相同 。
在这里我们来详细讨论一下 WM_PAINT消息 。 当调用成员函数 UpdateWindow( )或 RedrawWindow( )要求重新绘制窗口内容时,应用程序将收到 WM_PAINT消息 。 当窗口最小化后再还原或被其他窗口遮盖后又重新显示时,
则当前窗口中的内容必须重新绘制,消息 WM_PAINT就是为实现这个功能的 。
返回 22
4.4 Windows消息当向 Windows应用程序发送 WM_PAINT消息,应用程序检索到此消息后,就重新显示窗口中的内容 。 WM_PAINT消息的处理函数为 OnPaint( )。
函数原型为:
afx_msg void OnPaint( );
如果想详细了解所有的标准的 Windows消息,可以参阅
Visual C++ 6.0联机帮助中的有关内容 。
4.4.2 控件消息控件是一个小的子窗口,属于其他窗口 ( 如对话框等 ),
能够接受操作并象父窗口发送消息 。 常见的控件有按钮,
列表框,编辑框,复合框,滚动条等 。
在 Visual C++ 6.0中,对控件的操作都是通过生成相应的控件类来进行 。 这些控件类仅能发送少量特定的消息,这些消息就叫做控件消息 。 发送控件消息的控件在 Visual C++中返回 23
4.4 Windows消息使用唯一 ID号来进行标识,使用控件类来操纵。
控件消息分为两类:
1,从控件传给消息,通常这类消息的前缀的最后一个字符为 N;
2,由系统发送给控件的消息,这类消息的前缀的最后一个字符为 M。
例如,当用户对编辑框中的文本进行修改时,编辑框将发送给父窗口一条包含控件通知码 EN_CHANGE 的
WM_COMMAND消息 。 窗口的消息处理函数将以某种适当的方式对通知消息作出响应,如检索编辑框中的文本 。
与其他标准的 Windows消息一样,控件消息也是由窗口对象和视图对象进行处理 。
返回 24
4.4 Windows消息
4.4.3 命令消息命令消息主要包括由用户界面对象发送的 M_COMMAND
消息,用户界面对象是指菜单、工具栏、快捷键等。它和控件消息的区别在于:控件消息只能由特定控件向
Windows系统传送,而命令消息是由用户界面发送的,它可以被更多的对象处理。在文档对象、视图对象、窗体对象、控件对象中都能处理这种消息。
1,用户界面对象菜单、工具栏、快捷键等都是可以产生命令的用户界面对象。每个这样的对象都分配了一个 ID号,通过给对象和命令分配同一个 ID号,将用户界面对象和命令联系在一起。例如,选择程序中的 【 文件 】 菜单下的 【 打开 】
菜单项,则产生一条 ID_FILE_OPEN命令,然后通过消息映射调用函数 OnFileOpen()来进行处理。
返回 25
4.4 Windows消息
2,命令 ID
在 MFC编程中,命令完全由命令 ID来进行描述,命令 ID
分配给产生此命令的用户界面对象。通常情况下,命令 ID
是由它所表示的用户界面对象的功能来命名的。 MFC预定义了一些命令 ID,如 ID_EDIT_CUT,ID_FILE_SAVE 等,
而其他命令 ID则要由编程人员自己定义。
3,命令目标当用户界面对象被单击后,将调用处理函数来执行所产生的命令。 Windows把非命令消息的消息直接发送给窗口,
窗口中用于处理这些消息的处理函数将被调用。而对于命令消息,将把命令发送给多个目标,也就是命令目标,其中通常有一个要调用此命令的处理函数。
返回 26
4.5 消息的发送和接收的基本过程和机制在 Windows中,大部分的消息都是由用户和应用程序的相互作用而产生的 。 CWinApp类的成员函数 Run( )用于处理消息循环,它唯一的功能就是等待消息,并将消息发送到适当的窗口 。
当消息循环接收到一条 Windows消息时,它首先通过查询一种内部结构来确定消息要发送的窗口 。 这种内部结构把当前所有的窗口映像成其对应的窗口类 。 MFC的基类还能够检测这一目标类是否在其消息中为这一消息提供了处理函数入口 。 如果找到入口,则消息被送往处理函数,结束消息发送过程 。 如果消息无对应入口,则对目标类进行基类消息映射检测,沿着层次向上查找,
直到找到入口函数为止 。
对于命令消息来说,查找较为复杂。通常,每个命令目标类先把命令发送给某些其他的对象,使其他对象有返回 27
4.5 消息的发送和接收的基本过程和机制优先处理的机会。如果这些对象都不能处理此命令,则起始类检查自己的消息映射,若也不能处理此消息,则将命令发送给更多的命令目标。
在大多数情况下,命令目标将以下列顺序发送命令:
1,发送至当前活动的子命令目标对象;
2,发送至其本身;
3,发送至其他命令目标 。
【 例 】 在一个 MDI应用程序中,如果选择了,文件,菜单中的,保存,菜单项,则产生一条命令消息 。 我们假定命令处理函数是应用程序文档类的成员函数,则此命令的发送顺序为:
返回 28
4.5 消息的发送和接收的基本过程和机制
1,命令消息首先传给主框架窗口;
2,主框架窗口给当前活动的子窗口处理此命令的机会;
3,视图检查其消息映射,若没有找到处理函数,再把此命令发送给与其相连的文档;
4,文档检查其消息映射,如果找到命令的处理函数,则调用此函数,发送过程结束,否则继续下面的步骤;
5,将命令发送给文档模板,然后返回到视图,再返回边框窗口,边框窗口检查其消息映射;
6,命令回送到主边框窗口,主边框窗口检查自己的消息映射;
7,检测应用程序的消息映射,进到消息入口,并调用适当的处理程序。
返回 29
4.6 消息映射与消息处理函数
4.6.1 消息映射与消息处理函数的概念通过消息映射,消息就和它的处理函数对应起来 。
消息处理函数指的是与某个消息对应的函数 。 消息处理函数的执行是由其对应的消息引发的,某个类对象中的消息处理函数是与这个类对象能够得到的一个消息对应的,当这个消息发生时,这个函数就会被执行 。
消息处理函数的定义与使用方法与类的一般的成员函数不同。一般成员函数包括两部分:函数的定义部分和函数的实现部分;而消息处理函数除了这两部分以外,
还有消息映射部分。
返回 30
4.6 消息映射与消息处理函数
4.6.2 管理窗口消息处理函数利用 Class Wizard可以管理消息处理函数,Class Wizard
是一个非常强大有用的工具,我们可以用 Class Wizard来创建新类,定义消息处理函数,覆盖 MFC的虚拟函数,
从对话框,表单视图或记录视图的控件中获取数据 。
可以用三种方法来激活 Class Wizard对话框:
1,选择 【 View】 菜单中的 【 Class Wizard】 菜单项;
2,直接按下 Ctrl+W键;
3,在代码编辑窗口中单击鼠标右键 ( 此时,代码编辑窗口中必须有打开的文件 ),在弹出菜单中选择 【 Class
Wizard】 菜单项 。
返回 31
4.6 消息映射与消息处理函数当执行了以上操作,窗口中将弹出 【 MFC Class Wizard】
对话框。此时显示的是 【 Message Map】 选项卡。在这个选项卡的最上面有两个下拉列表框,【 Project】 列表中显示的是当前的项目名称,【 Class name】 列表中显示的是正在编辑的消息映射所属的类名。选项卡的中间也有两个多行的列表框。左边的 【 Object IDs】 列表框中显示的对象有三种类型:在 【 Class name】 栏中列出的类名、菜单项对象和其他可能在 【 Class name】 中所选的类传递消息的控件,当其中的某一个类被选中时,右面的 【 Messages 】
列表框就显示出此类的能捕获的所有 Windows消息。其中还列出了一些能够捕获的普通消息的虚函数。最下面
【 Member functions】 列表中显示的是与此消息相关的类的成员函数的列表。
返回 32
4.6 消息映射与消息处理函数在 【 MFC Class Wizard】 对话框中共有五个选项卡,分别说明如下:
1,【 Message Maps】 选项卡 用于进行消息映射的处理;
2,【 Member Variables】 选项卡 用于为对话框中的控件所用到的类创建成员变量;
3,【 Automation】 选项卡 帮助用户管理与 OLE自动化相联系的方法和属性;
4,【 ActiveX Events】 选项卡 帮助用户管理 ActiveX类支持的 ActiveX事件;
5,【 Class Info】 选项卡 显示类的一般信息,包括定义它的头文件和源文件,类名以及与之相联系的基类 。
返回 33
4.6 消息映射与消息处理函数
4.6.2.1 增加一个窗口消息以应用程序 MyExp为例,说明用 Class Wizard增加一个窗口消息处理函数的过程 。
1.在 VC++工作界面下打开 MyExp项目,并启动 Class
Wizard,进入对话框界面 。
2,从 【 Class Name】 复合框中选择视图类 CMyExpView,在
【 Object IDs】 列表框中就会列出各种消息来源的组件 。
3,从 【 Object IDs】 列表框中选择 CMyExpView,在列表框 【 Message】 中列出的就是 CMyExpView 类对象能够从窗口对象 CWnd接受到的窗口消息和各种可重载的虚函数 。
从中可以找到名为 WM_LBUTTONDOWN 的消息,用鼠标选中这个消息 。
返回 34
4.6 消息映射与消息处理函数
4,此时,【 Add Function】 按钮处于可执行状态,单击此按钮,就会在 CMyExpView类中增加一个被 CWnd保护的消息处理函数 OnLButtonDown。
5,在 【 Member functions】 列表框中能够发现这个函数及其对应的消息映射机制,O n L B u t t o n D o w n
ON_WM_LBUTTONDOWN。 在函数前有一个,W,标志,表示这个函数是一个窗口消息处理函数 。
6,单击 【 OK】 按钮,完成一个窗口消息处理函数的增加。
4.6.2.2 增加窗口消息处理函数的过程的分析以上介绍了用 Class Wizard增加一个窗口消息处理函数的过程,增加了该函数后,对于应用程序 MyExp
的代码做了如下的修改:
返回 35
4.6 消息映射与消息处理函数
1,在视图类 CMyExpView中,增加了消息处理函数的定义代码:
//省略以上代码
protected:
//{{AFX_MSG(CMyExpView)
afx_msg void OnLButtonDown(UINT nFlags,CPoint
point); //单击鼠标左键调用
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
//省略以下代码返回 36
4.6 消息映射与消息处理函数
2,在 CMyExpView 类的实现文件 MyExpview.cpp中,增加了函数的实际代码:
void CMyExpView::OnLButtonDown(UINT nFlags,CPoint point)
{
//TODO,Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags,point);
}
3,在实现文件 MyExpView.cpp中,还增加了函数的消息映射机制:
BEGIN_MESSAGE_MAP(CMyExpView,CView)
//{{AFX_MSG_MAP(CMyExpView)
返回 37
4.6 消息映射与消息处理函数
ON_WM_LBUTTONDOWN() //单击鼠标左键,
//OnLButtonDown 函数的消息映射
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT,CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT,view::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW,
CView::OnFilePrintPreview)
END_MESSAGE_MAP()
返回 38
4.6 消息映射与消息处理函数
4.6.2.3 Class Wizard 识别和处理窗口消息处理函数所需要的标识
1,窗口消息处理函数的定义在类的定义文件中,Class Wizard通过以下两行固定的代码来标识消息处理函数:
//{{AFX_MSG(CMyExpView) //Class Wizard标识消息
//处理函数定义的起始代码
//}}AFX_MSG //Class Wizard标识消息处理函数定义
// 的结束代码
AFX_MSG括号中的内容 (CMyExpView)是消息处理函数所在类的名称,只有将消息处理函数定义在以上两行代码间时,才能被 Class Wizard识别和处理 。
返回 39
4.6 消息映射与消息处理函数
2,窗口消息处理函数的实现在实现文件中,消息映射机制写在如下的两行代码间而被 ClassWizard识别:
//{{AFX_MSG_MAP(CMyExpView) //Class Wizard标识消
//息处理映射机制的起始代码
//}}AFX_MSG_MAP //Class Wizard标识消息处理
//映射机制的结束代码同样,AFX_MSG_MAP括号中的内容是拥用消息映射机制的类的名称,只有当一个消息处理函数的消息映射机制写在以上两行代码间时,才能被 Class Wizard 识别和处理 。
返回 40
4.6 消息映射与消息处理函数
4.6.2.4 删除窗口消息处理函数用 Class Wizard 删除窗口消息处理函数的方法很简单:
在操作界面中,从 【 Member Functions】 列表框中选择刚刚增加的 OnLButtonDown函数,这时 【 Delete Funtion】
按钮处于激活可执状态,单击此按钮,系统会提示是否对 OnLButtonDown函数进行删除,并提示必须用手工从实现文件中删除函数的实际代码,确认后就删除了这个消息处理函数 。
以上操作只是从视图类 CMyExpView 中删除了函数的定义代码,从实现文件中删除了映射消息机制,而对于实现文件中的函数实现代码,需要手工进行删除 。 这样做的目的是避免误操作而删除大量有用的代码 。
返回 41
本章小结返回 42
习题