




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第 7 章 MFC原理与方法,本章主要学习内容: Windows的编程机制 MFC的基本原理和使用方法: MFC类 MFC应用程序框架 MFC消息管理 MFC宏 常用的MFC类,Windows是一个多进程的图形窗口操作系统,DOS应用程序采用顺序执行过程,而Windows是一个基于事件的消息(Message)驱动系统。 Windows应用程序是按照“事件消息处理”非顺序的机制运行。当有某个事件(如单击鼠标、键盘输入和执行菜单命令等)发生时,Windows会根据具体的事件产生对应的消息,并发送到指定应用程序的消息队列;应用程序从消息队列中取出消息,并根据不同的消息进行不同的处理。,7.1 Win
2、dows编程基础,API(Application Programming Interface)是Windows操作系统与应用程序之间的标准接口,它提供了上千个标准函数、宏和数据结构的定义。 SDK API软件开发包,利用Win32 Application向导建立Windows应用程序框架,然后根据需要添加头文件、实现源文件和资源文件,并编写具体的程序代码。 例:编写一个名为Hello的类SDK应用程序,当单击鼠标时通过调用API函数,以弹出一个提示信息对话框。,7.1.1 关于API和SDK,1执行“File|New”菜单命令,在New对话框的Project页面中选择Win32 Applica
3、tion项目类型,输入程序名Hello。在向导第1步选择“A typital “Hello world!” application”项,单击Finish按钮。 2在窗口函数WndProc()的消息处理分支switch-case结构中添加WM_LBUTTONDOWN鼠标单击消息及其处理代码: case WM_LBUTTONDOWN: MessageBox(NULL, You pressed the left button of mouse !,Message,NULL); break;,在Windows中,用句柄(Handle)标识应用程序中不同的对象和同类对象中不同的实例,如一个具体的窗口、按
4、钮、输出设备、画笔和文件等。通过句柄可以获得相应的对象信息。常用的句柄类型有: HWND 、 HINSTANCE 、 HDC 、HCURSOR、HICON、HMENU等。 句柄常作为Windows消息和API函数的参数,在采用API方法编写Windows应用程序时要经常使用句柄。而采用MFC方法编写Windows应用程序时,由于对应的MFC类已对句柄进行了封装,大多数情况下不再需要访问句柄。,7.1.2 句柄,获取MFC类对象的句柄的两种方法:,通过访问类的public属性成员变量,如类CWnd的成员变量m_hWnd就是一个窗口对象的句柄。 先定义一个句柄,然后调用MFC类的成员函数Attac
5、h()将句柄与一个MFC类对象联系在一起,此时的句柄就成为该MFC类对象的句柄。在退出对象作用域之前,调用成员函数Detach()将句柄和对象进行分离。如下所示: CWnd myWnd; HWND hWnd; myWnd.Attach(hWnd); . . . . . . myWnd.Detach();,所谓消息就是用于描述某个事件发生的信息,而事件是对于Windows的某种操作。 事件和消息密切相关,事件是因,消息是果,事件产生消息,消息对应事件。所谓消息的响应,其实质就是事件的响应。 消息驱动是Windows应用程序的核心,所有的外部响应(如键盘、鼠标和计时器等)都被Windows先拦截,
6、转换成消息后再发送到应用程序中的目标对象,应用程序根据消息的具体内容进行处理。 消息不仅可由Windows发出,它也可由应用程序本身或其它程序产生。Windows为每一个应用程序都维护一个或多个消息队列,发送到每个程序窗口的消息都排成一个队列。,7.1.3 事件和消息,消息队列和在应用程序中的轮询处理,Windows消息分为三种类型:,标准Windows消息:以WM_前缀(但不包括WM_COMMAND)开始的消息,包括鼠标消息、键盘消息和窗口消息,如WM_MOVE 、WM_PAINT等。 控件通知(Control Notification)消息:对控件操作引起的消息,是控件和子窗口向其父窗口发
7、出的WM_COMMAND通知消息。例如,当用户修改了编辑控件中的文本后,编辑控件向其父窗口发送WM_COMMAND通知消息。 命令(Command)消息:由菜单项、工具栏按钮、快捷键等用户界面对象发出的WM_COMMAND消息。命令消息与其它消息不同,它可被更广泛的的对象如文档、文档模板、应用程序对象、窗口和视图等处理。,typedef struct tagMSG HWND hWnd; / 目标窗口句柄 UINT message;/ 消息标识 WPARAM wParam;/ 消息参数1(附加信息,16位) LPARAM lParam;/ 消息参数2(附加信息,32位) DWORD time;/
8、 消息发送时间 POINT pt; / 消息发送时鼠标的屏幕坐标 MSG;,消息用MSG结构表示:,Visual C+捆绑了微软的基础类MFC,编程时我们就可以利用类的可重用性和可扩充性,大大降低Windows应用程序设计的难度和工作量。,7.2 MFC微软基础类,MFC作为一个Windows编程类库,它包含了200多个类,封装了Windows的大部分编程对象以及与它们有关的操作。 虽然程序在功能上千差万别,但从本质上看,都可以分为用户界面设计、文件操作、数据库访问及多媒体使用等几部分。,7.2.1 MFC概述,MFC主要组成部分:类、宏和全局函数。 类是MFC中最主要的内容。MFC类是以层次
9、结构方式组织起来的。MFC中的类分成两部分,除了一些辅助类,大多数的MFC类是直接或间接从根类CObject派生而来。 几乎每一个派生层次都与一具体的Windows实例相对应,如文档类、窗口类和视图类等。 MFC宏主要功能:消息映射、运行时对象类型服务、诊断服务、异常处理。 MFC约定:全局函数以“Afx”为前缀,全局变量以“afx”为前缀。,7.2.2 MFC体系结构,首先要对Windows编程概念和API函数有一定的了解,如Windows API有哪些功能和哪些常用的数据结构等。 学会抽象地把握问题,不求甚解,不要一开始学习Visual C+就试图了解整个MFC类库。从理解和使用两个方面学
10、习MFC,理解MFC应用程序的框架结构。 先大体上了解MFC的概念、组成和基本约定,从简单的类入手,结合程序设计,由浅入深,循序渐进、日积月累。 编程时如果MFC某个类能完成所需要的功能,可以直接调用已有类的方法(成员函数)。否则,可以利用面向对象技术中的“继承”方法对MFC类的行为进行扩充和修改,从MFC中已有的类派生出自己需要的类。 学习MFC,另一点就是不要过分依赖于向导(Wizard)工具。向导能做许多工作,但同时掩饰了太多的细节。,7.2.3 学习MFC的方法,MFC应用程序对象之间的关系,7.3 MFC应用程序框架说明,MFC应用程序运行后各函数的调用关系,InitInstance
11、()函数是派生类唯一需要重载的函数,它负责应用程序的初始化,如初始化数据、创建文档模板、处理命令行以及显示应用程序主窗口。,MFC消息管理是MFC编程的一个重要内容,也是编写MFC应用程序的基础。 MFC应用程序消息处理的方式与SDK应用程序有所不同。MFC应用程序框架截取了Windows向应用程序发出的消息,再确定将消息发送给哪一个对象。 消息管理包括消息的发送和处理。对于消息发送,MFC提供了类似于API函数功能的消息发送函数,而MFC消息处理的内部机制则相对复杂一些。从编程的角度出发,我们只需了解其大致的原理。,7.4 MFC消息管理,MFC采用消息映射(Message Map)机制取代
12、C/C+语言中的switch-case结构来处理消息。 MFC消息映射机制包括一组消息映射宏。一条消息映射宏把一个Windows消息和其消息处理函数联结起来。 MFC应用程序框架提供了消息映射功能。 在类的实现源文件中用BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()宏来定义消息映射。 在类定义的结尾用DECLARE_MESSAGE_MAP()宏来声明使用消息映射。,7.4.1 MFC消息映射机制,BEGIN_MESSAGE_MAP(theclass, baseclass) /AFX_MSG_MAP(theclass) ON_ . . . . . . / MFC预定义
13、的消息映射宏 ON_MESSAGE(message , memberFxn) / 用户自定义的消息映射宏 . . . . . . /AFX_MSG_MAP END_MESSAGE_MAP(),MFC应用程序MESSAGE_MAP消息映射形式:,注意:特殊注解“/AFX_MSG_MAP”是ClassWizard类向导用于维护消息映射宏的标记,用户不要删除注解轻易修改注解内的代码。,启动ClassWizard,添加要求的三个消息处理函数,ClassWizard将在类的实现文件中添加三个消息映射宏和消息处理函数。消息映射宏如下: BEGIN_MESSAGE_MAP(CMainFrame, CFram
14、eWnd) /AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() / 由MFC AppWizard程序向导自动生成的消息映射 ON_WM_CLOSE() / 由ClassWizard类向导添加 ON_WM_DESTROY() ON_COMMAND(ID_EDIT_COPY, OnEditCopy) /AFX_MSG_MAP END_MESSAGE_MAP(),例 利用ClassWizard为框架类添加消息WM_CLOSE、WM_DESTROY及菜单项“Edit|Copy”的消息处理函数,分析ClassWizard完成了哪些工作。,class CMainFrame :
15、CFrameWnd public: CMainFrame(); protected: /AFX_MSG(CMainFrame) / 声明消息处理函数原形 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); / 由程序向导自动生成 afx_msg void OnClose(); / 由ClassWizard类向导添加 afx_msg void OnDestroy(); afx_msg void OnEditCopy(); /AFX_MSG DECLARE_MESSAGE_MAP() / 声明使用消息映射宏 ;,ClassWizard在类的定义
16、中声明了消息处理函数 :,发送消息到一个窗口可以采用传送(Send)或寄送(Post)方式,这两种方式之间的主要区别是消息被接收对象收到后是否立即被处理。Windows提供了三个API函数用于消息的发送。 函数SendMessage()用于向一个或多个窗口传送消息,该函数将调用目标窗口的窗口函数,直到目标窗口处理完收到的消息,该函数才返回。 函数PostMessage()用于向一个或多个窗口寄送消息,它把消息放在指定窗口创建的线程的消息队列中,然后不等消息处理完就返回。,7.4.2 消息的发送,函数SendDlgItemMessage()函数用于向对话框中指定的控件发送消息,直到目标控件处理完
17、收到的消息,该函数才返回。 MFC将这三个函数封装为CWnd窗口类的成员函数,封装了目标窗口句柄,它们将向调用它的窗口对象发送或寄送消息,如pMyView-SendMessage()的调用形式表示向pMyView所指对象发送消息。 与用户输入相关的消息(如鼠标消息和键盘消息)通常是以寄送(Post)的方式发送,以便这些用户输入可以由运行较缓慢的系统进行缓冲处理。而其它消息通常是以传送(Send)的方式发送,由于程序逻辑设计结构的限制或不同窗口之间数据的同步,程序员需要手工自定义一些消息。例如,如果需要在特定时间间隔内通知所有数据输出窗口重新取得数据,就必须采用定时器事件来产生特定的消息。 MF
18、C允许用户自定义消息,常量WM_USER(为0 x0400)与第一个自定义消息值相对应,用户必须为自己的消息定义相对于WM_USER的偏移值,。利用#define语句定义自己的消息,例如: #define WM_USER1 WM_USER+0 #define WM_USER2 WM_USER+1,*7.4.3 自定义消息处理,必须在函数返回类型前面加上afx_msg标识,如: afx_msg LRESULT memberFxn ( WPARAM wParam , LPARAM lParam); 其中,参数wParam、lParam用于传递消息的两个附加信息,自定义消息处理函数的声明:,ON_M
19、ESSAGE(message, memberFxn) 其中,message是消息名标识,memberFxn是对应的 消息处理函数。如: ON_MESSAGE(WM_MYMESSAGE, OnMyMessage),自定义消息映射宏的定义:,1首先利用MFC AppWizardexe向导创建一个名为Rotate的应用程序。利用ClassWizard类向导为CRotateView类生成消息WM_CREATE的消息处理函数,通过设置定时器在指定的时间间隔向窗口发送WM_TIMER消息。 SetTimer(1,200,NULL); / 启动定时器 2在文件RotateView.cpp开始位置定义一个用户
20、自定义消息:#define WM_MYMESSAGE WM_USER+1 利用ClassWizard为CRotateView类生成消息WM_TIME的消息处理函数:SendMessage(WM_MYMESSAGE);,例 编写一个自定义消息应用程序,程序启动后设置一个定时器,在WM_TIMER的消息处理函数中发送一个用户自定义消息,在对应的自定义消息处理函数中以动画的形式旋转显示一行文本。,3在类CRotateView的定义中声明自定义消息处理函数: afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); 在文件RotateView
21、.cpp消息映射BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间添加自定义消息映射宏: ON_MESSAGE(WM_MYMESSAGE,OnMyMyessage) 4在类CRotateView的定义中声明一个private属性、int型的成员变量m_dEscapement,它表示文本显示角度,并在类CRotateView的构造函数中初始化:m_dEscapement=0; 5在文件RotateView.cpp中手工添加自定义消息处理函数实现代码,完成以动画形式旋转显示一行文本的功能。 6利用ClassWizard生成消息WM_DESTROY的消息处理函数,在销毁已创建的定
22、时器:KillTimer(1);,宏就是用预处理指令#define定义一个标识符,用它来表示一个字符串或一段源代码。MFC宏作为MFC类库的一个组成部分在MFC应用程序中经常出现。MFC宏在Afxwin.h、Afx.h及Afxmsg_.h等MFC头文件中分别进行了定义。 MFC提供的宏有很多,常用的包括消息映射宏、运行时类型识别的宏、调试宏和异常宏等,下表列出了一般MFC编程时要用到的宏。,7.5 MFC宏,运行时类型识别RTTI(Run Time Type Information)是指在程序运行时允许确定对象的类型。MFC扩充了一般C+中运行时类型识别的功能,当一个类支持MFC的运行时类型识
23、别时,它允许程序获取对象的信息(如类名、所占存储空间大小及版本号等)和基类信息。 1. 宏RUNTIME_CLASS(class_name): 返回参数class_name所指定类的静态成员变量class#class_name的指针,该指针指向一个CRuntimeClass结构。,7.5.1 有关运行时类型识别的宏,2. 动态支持宏DECLARE_DYNAMIC()和IMPLEMENT_DYNAMIC(): 使用动态支持宏能够使CObject派生类的对象具有基本的类型识别机能,可以通过调用成员函数CObject:IsKindOf()测试对象与给定类的关系。 3. 动态创建宏DECLARE_DY
24、NCREATE()和IMPLEMENT_DYNCREATE(): 动态创建是动态支持的一个超集,除了基本的类型识别机能,使用动态创建宏能够使CObject的派生类具有在运行时动态创建对象的功能。 4. 序列化宏DECLARE_SERIAL() 和IMPLEMENT_SERIAL(),跟踪声明和断言在查找程序设计错误时是非常有用的。跟踪声明可以让程序在运行过程中遇到跟踪声明时在输出窗口显示指定的信息,而断言使程序在断言条件不成立时暂停程序的运行。MFC提供了一些跟踪声明和断言宏用于程序调试,这些宏只能用于DEBUG版本应用程序的调试状态。 1TRACE()宏语法说明如下: TRACE (); 其
25、中参数是由输出格式和变量等组成的输出表达式,其格式与函数printf()的参数一样,它指定调试时要在Output窗口输出的内容。,7.5.2 MFC调试宏,2、ASSERT断言宏 ( 参见p287),3、ASSERT_VALID断言有效宏 ( 参见p287-288),char* szName = “LiMing”; int nAge = 18; TRACE(“Name = %s, Age = %d n”, szName, nAge );,例1 对于以下代码:,调试时在Output窗口输出以下内容: Name = LiMing, Age = 18,例2 设自定义一个CFrameWnd的派生类CM
26、yFrame,在程序中构建一个与CMyFrame相关联的文档模板对象,并为构键的文档模板创建框架窗口: CMyFrame* pFrame=(CMyFrame*) AfxGetMainWnd(); ASSERT(pFrame-IsKindOf( RUNTIME_CLASS (CMyFrame); / 判断pFrame的类型 pFrame-DoSomeOperation();,7.6.1 CRuntimeClass结构 CRuntimeClass在MFC中是以结构的方式定义,它含有使用CRuntimeClass结构的类的有关信息,与CObject类一同实现运行时类型识别RTTI的功能。CRunti
27、meClass结构包含了类名、对象所占存储空间大小及类的版本号等成员变量和动态对象创建、派生关系判断等成员函数。 每个从CObject类派生的类都有一个CRuntimeClass对象同它关联。要使用CRuntimeClass结构,必须结合使用RUNTIME_CLASS()宏和其它有关运行时类型识别的MFC宏。,7.6 常用的MFC类,7.6.2 CObject类(MFC根类,是一个抽象的基类) 由于MFC中大部分类是从CObject类继承而来的,CObject类描述了几乎所有的MFC类的一些公共特性,CObject类为程序员提供了对象诊断、运行时类型识别和序列化等功能。 对象诊断。MFC提供了
28、两种诊断特性:利用成员函数AssertValid()进行对象有效性检查,使得类可以在继续运行前对自己进行正确性检查;利用成员函数Dump()输出对象的数据成员的值。 运行时访问类的信息:提供GetRuntimeClass()和IskindOf()两个成员函数来支持运行时类型识别。 对象序列化。,void CHuman:AssertValid() const CObject:AssertValid(); ASSERT(m_year0); ASSERT(m_year120); ,例1 通过“Insert|New Class”定义一个CObject的派生类CHuman。在类CHuman中重载Asse
29、rtValid()函数,利用ASSERT宏把人的年龄限制在一个合理的范围。,void CAssertView:OnDraw(CDC* pDC) CHuman man; man.m_year=200; man.AssertValid(); / 超出年龄范围,将断言失败 ,void CHuman:Dump(CDumpContext ,例2 在派生类CHuman中重载成员函数Dump(),输出数据成员m_year的值。,调用Dump()函数: CHuman* pMyPerson=new CHuman; pMyPerson-m_year=39; #ifdef _DEBUG / 调试时在调试器输出窗口显示m_year的值 pMyPerson-Dump(afxDump); #endif,7.6.3 CCmdTarget类 CCmdTarget类由CObject类直接派生而来,它负责将消息发送到能够响应这些消息的对象。它是所有能进行消息映射的MFC类的基类。 设置光标。CCmdTarget类定义3个函数用于改变光标状态:BeginWaitCursor()将光标改为沙漏形状,EndWaitCursor()将光标改回调用BeginWait- Cursor()之前的形
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 精炼2024西医临床考试试题及答案
- 系统架构设计师考试备考计划制定试题及答案
- 药剂市场机会分析试题及答案
- 育婴师的专业发展与培训试题及答案
- 系统架构设计师的思维导图构建试题及答案
- 放射三基训练试题及答案
- 留学逻辑考试题及答案
- 蔬菜鉴别测试题及答案
- 药剂类知识体系建设试题及答案
- 育婴师考试心理准备策略试题及答案
- 设备报修单表
- 心肺复苏急救步骤图例
- 2022-2023学年四川眉山仁寿新店镇小学校数学五年级第二学期期末学业质量监测试题含解析
- 初中化学-洁厕灵溶液主要成分的探究教学课件设计
- 高中数学说题课件
- 二年级数学欧利和他的懒弟弟优秀课件
- 2023年春江苏开放大学《江苏红色文化》过程性考核作业一二和综合大作业+参考答案
- 材料物理知到章节答案智慧树2023年南开大学
- 临床研究样本量计算器 CRESS V1.3
- 医患沟通技巧培训
- 压电陶瓷完整版课件
评论
0/150
提交评论