目录
前言
1.1 Windows应用程序概述
1.1.1 窗口
1.1.2 消息和事件
1.1.3 基本数据类型
1.1.4 句柄
2.2 MFC应用程序框架
2.2.1 创建MFC应用程序框架
2.2.2 MFC应用程序框架结构类
2.2.3 MFC应用程序分析
2.2.4 文档/视图结构
2.3 消息映射与消息处理
2.3.1 消息的类别及其描述
2.3.2 MFC消息映射机制
2.3.3 自定义消息处理
2.4 程序调试
2.4.1 查找源程序中的语法错误
2.4.2 调试器
2.4.3 跟踪调试程序
总结
前言
本篇文章介绍MFC应用程序
一、MFC应用程序概述
1.1 Windows应用程序概述
1.1.1 窗口
窗口是用户界面中最重要的部分。它是屏幕上与一个应用程序相对应的矩形区域,是用户与产生该窗口的应用程序之间的可视界面。
1.1.2 消息和事件
Windows是一个基于事件的消息驱动系统,Windows应用程序是按照“事件→消息→处理” 的机制运行的。
所谓消息,就是用于描述某个事件发生的信息,而事件是对于Windows的某种操作。事件是因,消息是果,事件产生消息,消息对应事件。
所谓消息的处理,其实质就是事件的处理。当有某个事件(如单击鼠标、键盘输入和执行菜单命令等)发生时,Windows会根据具体的事件产生对应的消息,并发送到指定应用程序的消息队列。应用程序从消息队列中取出消息,并根据不同的消息进行不同的处理。
1.1.3 基本数据类型
Windows编程中常用的基本数据类型的别名。
1.1.4 句柄
句柄是Windows编程的基础,所谓句柄就是Windows使用的一种无重复整数。
句柄主要用来标识应用程序中的一个对象,如窗口、实例、菜单、内存、输出设备、控制或文件等。
Windows常见的公用句柄类型如下表所示:
2.2 MFC应用程序框架
2.2.1 创建MFC应用程序框架
下面通过一个实例介绍利用MFC AppWizard[exe]创建应用程序框架的步骤。
【例2.1】编写一个SDI单文档应用程序Li2_1,程序运行后,通过消息框输出“这是一个单文档应用程序!”的提示信息。
(1) 选择File菜单下的New菜单项,系统弹出New对话框。
(2) MFC AppWizard-Step 1对话框主要用于选择应用程序类型。AppWizard可以创建3种类型的应用程序框架。
(3)MFC AppWizard-Step 2 of 6对话框中主要用于选择应用程序所支持数据库方式。
(4)在MFC AppWizard-Step 3 of 6对话框中选择应用程序所支持的复合文档类型。
(5)在MFC AppWizard-Step 4 of 6对话框中设置应用程序的外观特征。
(6) 在MFC AppWizard-Step 5 of 6对话框中设置应用程序的风格。
(7) 在MFC AppWizard-Step 6 of 6对话框中,可以设置向导生成的文件名和类名。
(8)打开项目工作区中的ClassView类视图,单击CLi2_1View类左边的“+”展开视图类,双击打开OnDraw()函数,并添加代码。
void CLi2_1View::OnDraw(CDC* pDC)
{
CLi2_1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
MessageBox("这是一个单文档应用程序!",
"消息框",
MB_ICONEXCLAMATION|MB_OKCANCEL);
}
(9) 选择Build菜单中的Build Li2_1.exe菜单项,对工程进行编译和链接,生成可执行文件。再选择Build菜单中的Execute Li2_1.exe菜单命令运行程序。
2.2.2 MFC应用程序框架结构类
MFC应用程序框架结构类的继承关系:
1.CObject类
CObject是MFC类库的根类,它几乎描述了所有MFC类的一些公共特性,并且给所有由它派生出的类提供了3种重要特性,即:串行化支持、运行时类信息支持以及诊断和调试支持。
2.CCmdTarget类
命令类CCmdTarget是CObject的子类,它是MFC库中所有具有消息映射属性的类的公共基类。从CCmdTarget派生的类能在程序运行时动态创建对象和处理命令消息。
3.CWinApp类
应用程序类CWinApp是CWinThread的子类,封装了初始化、运行、终止应用程序的代码。可以由此派生自己的应用类。
4.CWnd类
窗口类CWnd提供了MFC中所有窗口类的基本功能。从CWnd派生的类可以拥有自己的窗口,并对它进行控制。
5.CFrameWnd类
CFrameWnd类是CWnd类的派生类。它是所有其他框架窗口类的基类,主要用来管理一个窗口。
CFrameWnd类的对象是一个框架窗口,包括边框、标题栏、菜单、最大化按钮、最小化按钮和一个激活的视图。CFrameWnd类支持单文档界面,对于多文档界面,使用它的两个派生类CMDIFrameWnd和CMDIChildWnd。CMDIFrameWnd类用于MDI的主窗口,CMDIChildWnd类用于MDI的子窗口。
6.CView类
视图类CView是CWnd类的子类。视图类及其派生类用于管理框架窗口的客户区。
7.CDocument类
文档类CDocument负责装载和维护文档。文档包括应用程序的工作成果或环境设置数据等,可以是程序需要保存的任何内容。
一个MFC应用程序并不直接操作上述类,而是以上述类为基类派生新的类,从而构建Windows应用程序的基本框架。
例如,应用程序Li2_1中的类与这些基类的派生关系:
2.2.3 MFC应用程序分析
1.应用程序向导生成的文件
下面以例2.1中创建的应用程序Li2_1为例,介绍MFC AppWizard[exe]向导所生成的各类文件及功能。
(1) 头文件与实现文件
- MainFrm.h和MainFrm.cpp:定义和实现窗口框架类CMainFrame。
- CLi2_1Doc.h和CLi2_1Doc.cpp:定义和实现文档类CLi2_1Doc。
- CLi2_1View.h 和CLi2_1View.cpp:定义和实现视图类CLi2_1View。
- CLi2_1.h 和CLi2_1.cpp:定义和实现应用程序类CLi2_1App。
- Resource.h:定义工程中所有资源标识符,给资源ID分配一个整数值。
- StdAfx.h和StdAfx.cpp:用于建立一个预编译的头文件CLi2_1.PCH和一个预定义的类型文件StdAfx.obj。
(2) 资源文件
- Li2_1.rc和Li2_1.rc2:Li2_1.rc文件是程序所使用的所有Windows资源的列表。
- Li2_1.ico:应用程序的图标所使用的图标文件。
- Li2_1Doc.ico:应用程序的文档图标文件。文档图标一般显示在多文档程序界面上。
- Toolbar.bmp:工具栏按钮的位图文件。
(3) 项目工作区文件和工程文件
- Li2_1.dsw:保存当前工作区所包含的工程的信息。
- Li2_1.dsp:包含当前工程的设置、工程中的文件等信息。
(4) 其他文件
- Li2_1.clw:该文件是类信息文件。它保存了ClassWizard编辑现有类或增加新类时需使用的类信息,同时还保存了创建、编辑消息映射和成员函数所需的信息。
- ReadMe.txt:该文件是工程自述文件。主要介绍所创建文件的内容和功能,以及添加用户代码、更改使用语言的方法。
2.应用程序的执行过程
- 启动:创建应用程序对象theApp、调用应用程序类的构造函数初始化对象theApp。
- 应用程序框架调用MFC提供的AfxWinMain( )主函数。
- AfxWinMain( )主函数,首先通过调用全局函数AfxGetApp( )来获取theApp的指针pApp;
- 然后通过该指针调用theApp的成员函数InitInstance( )来初始化应用程序。
在应用程序的初始化过程中,同时还构造了文档模板,产生最初的文档、视图和主框架窗口,并生成工具栏和状态栏。
- 当InitInstance( )函数执行完毕后,WinMain( )函数将调用成员函数 Run( ),进入消息处理循环;
- 函数Run( )收到WM_QUIT消息。
- MFC首先调用CWinApp类的成员函数ExitInstance( );
- 然后调用静态对象的析构函数;
- 退出应用程序,将控制权交给操作系统。
消息对话框
一种简单的对话框,用户可以直接调用消息对话框函数来使用它,而不需要自己创建。Visual C++提供3个消息对话框函数,它们的原型为:
int AfxMessageBox(LPCTSTR lpText,UINT nType=MB_OK,UINT nIDHelp=0);
int MessageBox(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT nType);
int CWnd::MessageBox(LPCTSTR lpText,LPCTSTR lpCaption=NULL,UINT nType= MB_OK);
2.2.4 文档/视图结构
文档/视图体系结构是MFC应用程序框架结构的基石,它定义了一种程序结构,这种结构利用文档对象保存应用程序的数据,依靠视图对象控制视图显示数据,文档与视图的关系是一对多的关系,也就是说,文档中的数据可以以不同的方式显示。
2.3 消息映射与消息处理
2.3.1 消息的类别及其描述
Windows消息主要有3种类型:标准Windows消息、控件消息和命令消息。
1.标准Windows消息
- 除WM_COMMAND以外,所有以“WM_”为前缀的消息都是标准Windows消息;
- 由窗口类或视图类处理;
- 都有默认的处理函数,它们在CWnd类中进行了预定义。
标准的Windows消息又分为3类:
键盘消息、鼠标消息和窗口消息。
(1)键盘消息
键盘消息与键盘某个键的动作相关联。常见的键盘消息有以下几种。
- WM_KEYDOWN、WM_KEYUP:按下、释放非系统键产生的消息。
- WM_CHAR:输入非系统字符时产生的消息。
(2) 鼠标消息
鼠标消息涉及到鼠标的单击、双击、拖动等。常用的鼠标消息有以下几种。
- WM_MOUSEMOVE:鼠标移动时产生的消息。
- WM_RBUTTONDOWN:鼠标右键按下时产生的消息。
- WM_LBUTTONDOWN:鼠标左键按下时产生的消息。
- WM_LBUTTONDBLCLICK:鼠标双击时产生的消息。
(3) 窗口消息
窗口消息一般与创建窗口、绘制窗口、移动窗口和销毁窗口等动作有关。
在MFC应用程序中,窗口消息是由视图类、窗口类及它们的派生类处理的。
2.控件消息
控件消息是指控件或其他子窗口向父窗口发送的WM_COMMAND消息。
与其他标准的Windows消息一样,控件消息也应该在视图类、窗口类中进行处理。但是,如果用户单击按钮控件时,发出的控件通知消息BN_CLICKED将作为命令消息来处理。
3.命令消息
命令消息是由菜单项、工具栏按钮、快捷键等用户界面对象发出的WM_COMMAND消息。
命令消息与其他消息不同,它可被更广泛的对象如文档、文档模板、应用程序对象、窗口和视图等处理。
2.3.2 MFC消息映射机制
- MFC采用消息映射来处理消息;
- 消息映射机制包括一组消息映射宏,用于把一个Windows消息和其消息处理函数联系起来。
- 所有从CCmdTarget类派生出来的类都能够拥有自己的消息映射。
- DECLARE_MESSAGE_MAP( )
- BEGIN_MESSAGE_MAP(MyClass, MybaseClass)
- END_MESSAGE_MAP( )
为了使用消息映射宏:
- 首先在类定义的结尾用DECLARE_MESSAGE_MAP( )宏来声明使用消息映射,该宏表示在为各个处理函数所写的类声明之后存在消息映射条目,这些函数是该类的成员函数。
- 然后在类的实现源文件中用BEGIN_MESSAGE_MAP( )和END_MESSAGE_MAP( )宏来定义消息映射。
MFC应用程序MESSAG_MAP消息映射的形式如下:
BEGIN_MESSAGE_MAP(MyClass, MybaseClass)
//{ { AFX_MSG_MAP (MyClass) //ClassWizard维护消息映射宏的标记
ON_... //MFC预定义消息映射宏
ON_MESSAGE(message, memberFun)//用户自定义消息映射宏
//} } AFX_MSG_MAP
END_MESSAGE_MAP()
其中,MyClass是拥有消息映射的派生类名,MybaseClass 是其基类名。
2.3.3 自定义消息处理
自定义消息处理:定义消息名、分配ID值及完成消息映射。
Windows将所有的消息值分为4段:
- 0x0000~0x03FF段:用于Windows系统消息
- 0x0400~0x7FFF段:用于用户自定义的窗口消息
- 0x8000~0xBFFF段:为Windows保留值
- 0xC000~0xFFFF段:用于应用程序的字符串消息。
常量WM_USER(为0x0400)与第一个自定义消息值相对应,用户必须为自己的消息定义相对于WM_USER的偏移值,利用#define语句直接定义自己的消息,如下所示:
#define WM_USER WM_USER+3 ;// 自定义消息WM_USER
也可以调用窗口消息注册函数RegisterWindowMessage( )来定义一个Windows消息,由系统分配消息一个整数值。该函数原型为:
UINT RegisterWindowMessage(LPCTSTR lpString);
其中参数lpString是要定义的消息名,调用成功后将返回该消息的ID值。
2.4 程序调试
程序调试分为源程序语法错误的修改和程序逻辑设计错误的修改两个阶段,编译器只能找出源程序的语法错误,程序的逻辑设计错误只能靠程序员利用调试工具来手工检查和修改。
2.4.1 查找源程序中的语法错误
语法错误分为:
- 一般错误(error):出现该错误时将不会产生可执行程序;
- 警告错误(warning):出现该错误时能够生成可执行程序,但程序运行时可能发生错误,严重的warning错误还会引起死机现象。
如果程序有语法错误,则在执行编译、链接命令时,Visual C++编译器将在输出窗口中给出语法错误提示信息,但链接错误提示信息不能给出错误发生的具体位置。
在输出窗口中双击错误提示信息或按F4键可以返回到源程序编辑窗口,并通过一个箭头符号定位到产生错误的语句。
2.4.2 调试器
为了查找和修改程序中的逻辑设计错误,Visual C++ IDE提供了重要的调试工具——Debug。
单击Build | Start Debug菜单中的菜单项,可以启动Debug。
2.4.3 跟踪调试程序
即使源程序没有语法错误,但最后生成的可执行程序也没有像程序设计要求的那样运行,这类程序设计上的错误被称为逻辑设计错误或缺陷(bug)。
跟踪调试程序是查找此类逻辑设计错误方法中最常采用的动态方法。跟踪调试的基本原理就是在程序运行过程的某一阶段观测程序的状态。而在一般情况下程序是连续运行的,所以我们必须使程序在某一点停下来。
1.设置断点
选择Edit菜单下的Breakpoints菜单项,显示Breakpoints对话框。
2.控制程序运行
- Step Over:运行当前箭头指向的代码(只运行一条代码)。
- Step Into:如果当前箭头所指的代码是一个函数的调用,则用Step Into进入该函数并进行单步执行。
- Step Out:如果当前箭头所指向的代码是在某一函数内部,用它可使程序运行至函数返回处。
- Run to Cursor:使程序运行至光标所指的代码处。
3.观察数据变化
在调试过程中,可以通过Watch和Variables窗口查看当前变量的值。
总结
学业不如就业,就业不如创业,创业追求事业,事业成就伟业。红尘万丈一腔情,千秋伟业天地人,事在人为,敢作敢为,一切人为,拼搏创业—基业长青!