1、Visual C+程序设计重庆科技学院Visual C+程序设计大作业专业班级: 学 号: 姓 名: 成 绩: Visual C+程序设计1第 1章 Win32 程序设计和 MFC程序设计1 Win32控制台程序设计和基于 MFC的 GUI程序设计特点1.1Win32控制台程序 控制台程序在 Windows程序的角色中是非常强大且方便的,它没有复杂的 GUI,完全是 32位的程序,能够调用除 GDI函数之外的 API,支持多线路,支持 MFC等。而汇编语言有着速度快和与硬件直接打交道的能力,其高质量的代码,较少的代码冗余,最快的运行速度,在某些方面有着突出的优势。所以Windows控制台程序的
2、汇编语言写直接和硬件相关的控制台程序更能体现其性能的优越性。在 Windows系统下,绝大多数应用程序都是图形窗口界面,程序的运行靠消息来驱动。在 32位保护模式下工作的 Windows可兼容以前 16位保护模式下工作的 DOS程序,Windows 操作系统中保留了这种字符终端界面,如 ipconfig程序和 ping程序等。而采用了字符终端界面的好处是,在有些场合,用户对程序执行的界面要求不高,而更为关注的是程序的性能,次时程序员可以不用为提供友好的用户界面花费心思,而把精力投入到程序功能的实现上。Win32控制台程序使用标准的输入输出设备,支持命令行的重定向操作,也可以输出彩色的文本等。W
3、in32控制台函数要求将控制台句柄作为第一个参数传递给它们,句柄是一个 32位的无符号数据,用来唯一确定一个对象,如位图、画笔或某个输入输出设备等。Win32控制台是在保护模式下运行。Win32 控制台使用的是 Windows图形界面程序使用的那些库函数。Win32 控制台是一种具有 DOS界面的 32位 Windows程序,它不能在 DOS环境下运行,同时它为字符模式应用程序提供了 I/O借口,一个控制台有一个输入缓冲区和一个或多个屏幕缓冲区组成。Win32控制台有一个输入缓冲区,其中包括一个输入动作记录的队列,每个输入动作,如键盘敲击动作、鼠标移动或按键等都会在缓冲区中产生一个记录,Rea
4、dConsole 等高级操作函数过滤并处理这些输入的数据,并且返回一个字符串。ReadConsole 函数提供了将文本输入读取到一个缓冲区的便捷方法。Win32控制台程序界面类:头文件:windesign.h/划线类(专供 windowDesigner.h使用)wndowDesigner.h/画界面类其他要包含的 cpp文件:questionwin.cppwindesign.cppwindowDesigner.cppVisual C+程序设计21.2 MFC的 GUI程序设计MFC的 GUI程序设计从涉及图形用户的框架结构及实现人机交互入手,体现了用 C+语言进行图形用户界面设计的优越性。运用
5、 MFC进行界面菜单和对话框的设计,为平台实现提供了可视化环境;使用图片图像处理软件,为实现可视化美观设计,提供了一个良好的界面交互环境。MFC的 GUI程序设计是实现界面可视化设计的核心,配合动态链接库实现界面设计。MFC 的 GUI程序设计是 C+语言走向真正实用化,以及研究者实现进一步发展的基础。MFC 的 GUI程序设计使得界面设计不再是单纯的美术绘画,需要定位使用者、使用环境、使用方式。2程序设计概述2.1 Win32程序设计概述Windows程序的进行是依靠外部发生的事件驱动。程序不断等待(利用一个 while回路即 while循环),等待任何可能的输入,然后作出判断,再做适当的处
6、理。Windows 是一个多任务的操作系统,也就是说,在 Windows中可以有多个应用程序的实例正在运行。Windows时刻监视着用户的一举一动,并分析用户的动作与哪个应用程序相关,然后,将用户的动作以消息的形式发送给该应用程序,应用程序时刻等待着消息的到来,一旦发现它的消息队列中有未处理的消息,就获取并分析该消息,最后,应用程序根据消息所包含的内容采取适当的动作来相应用户所进行的操作。图 1所示给出了一般的 Windows应用程序的执行流程。图 1 Windows应用程序的执行流程Visual C+程序设计3Windows程序分为“程序代码”和“UI 资源”两大部分,这两部分最后用 RC编
7、译器整合为一个完整的 EXE可执行文件,所谓 UI资源是指功能选单、对话框外貌、程序图标、光标形状等。这些 UI资源的实际内容是(二进位码)借助各种工具产生,并一各种扩展名存在,如.co、.bmp、.cur 等。程序员必须在一个所谓的资源描述文档(.rc)中描述它们。在 RC编译器(RC.EXE)读取 RC文件的描述后,将所有 UI资源集中,并制作出一个.RES 文档,再与程序代码结合起来,这才是一个完整的 Windows可执行文档。2.2 MFC程序设计概述MFC类库包含了在一百多个程序开发中最常见的对象。在进行程序设计的时候,如果类库中的某个对象能完成所需要的功能,那么此时只要简单的调用已
8、有对象的方法就行了。2.2.1 MFC特性 封装特性:构成 MFC框架的是 MFC类库,而 MFC类库是 C+类库。这些类库封装了 Win32应用程序编程接口、应用程序的概念、OLE 特性、ODBC 和 DAO数据访问的功能等。 继承特性:MFC 抽象出众多类的共同特性,并设计出一些基类作为实现其它类的基础。这些类中,最重要的类是 CDbject和 CCmdTarget。程序员可结合实际,从适当的 MFC类中派生出自己的类,实现特定的功能,达到编程的目的。针对每一种不同的对象,MFC 都设计了一组类对这些对象进行封装,每一组类都有一个基类,从基类派生出众多更具体的类。这些对象主要包括:窗口对象
9、,基类是 CDnd;应用程序对象,基类是 CWinThread;文档对象,基类是 CDocument。 虚拟和消息映射:MFC 以“C+”为基础,支持虚拟函数。通过虚函数和消息映射,MFC 类提供了丰富的编程借口。在程序员继承基类的同时,把自己实现的虚函数和消息处理函数嵌入 MFC的编程框架中。MFC 编程框架将在适当的时候 、适当的地方来调用程序的代码。2.2.2 MFC程序设计思想MFC实现了对应用程序概念的封装,把类类的继承、动态约束、类的关系和相互作用等封装起来,这样封装的结果是一套开发模板(或者说是模式)。这些模板都采用了以文档/视图为中心的思想,每一个模板都包含一组特定的类。下面我
10、讲给出一个基于多文档的 MFC实例。用 AppWizard产生一个 MDI工程 Test,并创建了一系列文件,构成了一个应用程序框架。这些文件份 4类:头文件(.h),实现文件(.cpp),资源文件(.rc),模块定义文件(.def)。MDI 应用程序的组成如下图所示,其中箭头表示信息流向。Visual C+程序设计4应用程序对象CWinApp文档模板对象CDocTemplate文档对象CDocument主边框窗口对象CMDIFrameWnd状态栏对象CStatusBar工具条对象CToolBar文档边框窗口对象CMDIChildWnd视对象CView图 2 一个 MFC MDI应用程序的构成
11、该 MDI应用程序的主体是从 CwinApp、Cdocument、Cview、CMDIFrameWnd、CMDIChildWnd 类对应地派生出 CtestApp、CTestDoc、CTestView、CMainFrameWnd、CchildFrame5 类,这 5类的实例分别是应用程序对象、文档对象、视对象、主框架窗口对象和文档框架窗口对象。主框架窗口对象包含了视窗口、工具条和状态栏。2.3 MFC与 Win32的关系MFC本身就是一个庞大的 C+类库,这些类能较好地实现对 Win32API的封装,为应用开发提供了极大的方便。同时,MFC 依然支持 Win32 API的直接调用,这样基于 M
12、FC的程序设计中可以像在 Win32编程中一样直接使用 API。另外,MFC 除了对 Win32 API实现封装外,同时还封装了 OLE API、ODBC API 等底层 API函数的功能,如对 Win32 API实现的封装类似,为开发人员提供更高一层的接口,大大简化了 Windows编程。进一步来讲,MFC 比较彻底的封装了 Win32软件开发工具包(SDK)中的结构。功能,它为编程者提供了一个应用程序框架。Visual C+程序设计53应用程序的工作原理3.1 MFC与 Win32面向对象编程方式面向对象的编程方法具有封装、继承和多态三个特征以使它和其他编写方法相区别。封装对外界屏蔽数据好
13、热过程实现的内部细节,而继承和多态则可以大大简化编程的工作量。3.1.1 Win32面向对象编程方式Win32编写采用的是面向对象的编写方法,如:OOP,Object Oriented Programming。在 Win32中,程序的基本单位不是过程和函数,而是窗口。一个窗口是一组数据以及处理这些数据的窗口函数的集合。Win32 程序的执行过程本身就是窗口等对象的创建、处理和消亡的过程。Win32 中消息的发送可以理解为一个窗口对象请求服务的过程。由于 Win32应用程序的复杂性,从图形用户界面到整个应用程序,都是采用面向对象的方法组织的。Win32 中的对象可以是所有的规范部件,如窗口、菜单
14、、工具栏、按钮、文本框、以及程序模块等。从用户的观点看,Win32 应用程序有一个窗口,窗口上有若干菜单、命令按钮、图标等界面图形元素;而窗口背后是一些对应的程序。Win32系统给每个对象分配一个“句柄”(handle),它是一个 4字节长的整数值,是对象的唯一内部编号。应用程序通过句柄访问相应的对象。每个对象除了句柄外,还有一个对象标识符 ID,可看作是对象的外部名。ID 与句柄的区别主要在于:ID 可以是用户自行设定的;而句柄是系统内定的,对用户是透明的,这能防止应用程序直接访问对象的内部信息。3.1.2 MFC与 Win32面向对象编程方式从 MFC的面向对象模型看,一个 Win32应用
15、程序可以拆分成许多功能独立的对象,各自负责不同类型的工作,其最基本的构成对象可以分为两大类:程序对象和窗口对象。一个应用程序的执行就像一场舞台演出。应用程序对象是幕后人员(导演、剧务等),它们负责安排并指挥“演员”(窗口)上场,准备和调度各种演出“资源”(如菜单、工具栏、图标等)。从操作系统来看,具有“法人”地位的是应用程序对象而非窗口对象,应用程序可以占有 CPU时间和内存空间,还可拥有演出所需的“资源”。3.2窗口对象Visual C+程序设计6窗口是应用程序基本的操作单元,应用程序的运行过程即是窗口内部、窗口与窗口之间、窗口与系统之间进行数据处理与交换的过程。3.2.1 Win32应用程
16、序窗口对象在 Win32应用程序中,除了应用程序对象外,另一个重要的对象就是窗口对象。在基于 Windows API的应用程序中,通常通过调用 RegsiterClass来注册窗口类及调用 CreateWindow创建基于那个类的窗口来创建它的主窗口。在 windows程序先调用 API函数(CreateWindow)产生窗口之前,我们先要把窗口的属性设定好,如窗口的“外貌”和“行为”,外貌就是一个窗口的边框、颜色、标题、位置等等,行为就是接受消息后的反应(具体就是窗口函数)。注册窗口的 API函数是 MyRegisterClass。然后调用CreateWindow产生窗口。为了显示窗口,要调
17、用函数 ShowWindow。为了驱动窗口的绘图操作,调用UpdateWindow函数,传送一个 WM_PAINT给窗口。窗口函数通常利用 switch/case方式判断消息的种类,来决定处理的方式,它被设计为一种 call back 函数。被 Windows系统调用。LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)Win32应用程序中,窗口函数是采用 switch/case的机制来处理消息相应的。3.2.2 MFC应用程序窗口对象在一个应用程序中,除了应用程序对象外,另一个重要的对象就是窗
18、口对象。在基于 Windows API的应用程序中,通常通过调用 RegsiterClass来注册窗口类及调用 CreateWindow创建基于那个类的窗口来创建它的主窗口。MFC 程序通过创建一个窗口类对象的方式来创建窗口。在示例程序中,通过如下的语句来创建窗口:m_pMainWnd=new CMainWnd();new操作符创建对象,对象的构造函数创建应用程序的窗口。用 new返回的指针可用于访问对象的成员函数。在示例程序中,CMainWnd 类的说明如下:class CMainWnd:public CFrameWnd/类 CFrameWnd的派生类 CMainWnd的定义public:C
19、MainWnd(); /派生类 CMainWnd的定义protected:afx_msg void OnPaint(); /重画消息处理函数DECLARE_MESSAGE_MAP() /声明类 CMainWnd将对消息进行处理Visual C+程序设计7;CMainWnd类的基类是 CFrameWnd,CFrameWnd 类本身又是从 CWnd类派生出来的。CFrameWnd 类收缩了类 CWnd的定义,以便包含用作 SDI应用程序的主窗口。CMainWnd 构造函数只包含两条语句,即创建一个字符串对象和对窗口对象的 Create函数的调用:CMainWnd:CMainWnd() /类 CMa
20、inWnd的构造函数CString WndClass=AfxRegisterWndClass( /注册窗口类CS_HREDRAW|CS_VREDRAW, /指定窗口风格NULL, /指定窗口中所使用的光标(HBRUSH):GetStockObject(LTGRAY_BRUSH), /指定画刷LoadIcon(AfxGetInstanceHandle(),“DemoIcon“)/指定代表应用程序的图标); Create(WndClass,“一个简单的应用程序“ );Create函数用来创建框架窗口,它是由 CFrameWnd定义的。它的主要功能就是创建一个窗口对象。关于窗口的各个属性可以通过传递
21、给函数 Create的各个参数来控制。3.3应用程序对象与 Win32应用程序相比较,每一个 MFC程序都必须有且只有一个有 CWinApp派生的类对象。基于MFC的应用程序其核心是应用程序对象,它的类是由 MFC的 CWinApp类派生的。具体地讲就是上例中的CMyApp类。在 CWinApp类中提供了一些用于初始化应用程序,保存程序设置到磁盘文件之类的公用应用层操作。MFC 应用程序有且只有一个应用程序对象,且该对象必须用全局作用域来说明,因此它将在应用程序一开始就被创建。上面的的 MFC应用程序从 CWinApp派生出一个类,并用创建应用程序的主窗口的某个类重载InitInstance成
22、员函数。上面的程序中派生的应用程序类称为 CMyApp,并且定义该类的对象 MyApp为全局对象:class CMyApp:public CWinApp / CWinApp 派生/类 CMyApp的定义public:BOOL InitInstance(); /派生类中对基类 InitInstance函数的重载;CMyApp MyApp; /声明类 CMyApp的对象一个应用程序的生存周期中只调用 InitInstance函数一次,对这个函数的调用刚好在应用程序开始之后,但在应用程序的窗口显示之前。事实上,除非在 InitInstance函数中实现创建窗口的操作,否则应用程序就没有窗口。函数 U
23、pdateWindow完成创建的窗口的更新操作,它实际上是执行一个强迫重新绘制窗口的操作。由于 WinMain函数的执行依赖于应用程序对象,因此在 WinMain函数的执行前应用程序对象必须要在内存中存在。Visual C+程序设计8在应用程序启动后,由 MFC供给的 WinMain调用命名为 AfxWinInit的函数来初始化应用程序框架。AfxWinInit的任务包括将传递到 WinMain的 hInstance,hPrevInstance,lpCmdLine 及 nCmdShow的参数复制到应用程序对象的成员中,并定义几个预定义的窗口类。如果 hPrevInstance是 NULL值,W
24、inMain就调用应用程序对象的 InitApplication函数。由于 hPrevInstance在 Win32 环境下总是NULL,因此 32位的 MFC应用程序能用 InitApplication初始化它本身,正像 InitInstance一样容易。如果 AfxWinInit、InitApplication 和 InitInstance函数中的任何一个返回 0,则表示程序执行过程中出现了一个错误,这时 WinMain就调用 AfxWinTerm去消除,然后用一个返回语句终止。只有在所有的这些函数都返回 TRUE时,WinMain 函数才执行下一个关键步骤。调用应用程序对象的 Run函数
25、,对这个函数的调用将开始应用程序的消息循环,当发现消息循环队列空时就调用函数 OnIdle进入空闲杂务的处理。消息循环直到 WM_QUIT消息传给队列为止。此时,Run从循环中中端,调用 ExitInstance并返回到 WinMain。WinMain 函数通过调用 AfxWinTerm函数来清除分配给应用程序的资源和释放内存空间。在 AfxWinTerm函数执行完成后,整个应用程序也就结束了。4 应用程序结构4.1主函数4.1.1 Win32应用程序主函数所有的 Windows应用程序都有主函数 WinMain,为了与 DOS C程序的主函数名称相区别,Win32应用程序的主函数名称为 Wi
26、nMain. WinMain函数的原型为:Int WINAPI WinMain(HINSTANCE hInstance, /当前应用程序实例的句柄HINSTANCE hPrevInstance, /前一个应用程序实例的句柄LPSTR lpCmdLine, /指向本程序命令的指针Int nCmdShow, /决定应用程序窗口显示方式的标志);函数名前面的关键字 WINAPI表明这个函数是一个由系统调用的函数。主函数共有两个任务是创建应用程序窗口和建立消息循环。主函数至少要调用七个 API函数,其中四个用来创建显示应用程序窗口,三个用来建立消息循环。 窗口类型:一个窗口只能有一个窗口函数,但多个窗
27、口可以工业一个窗口函数。 注册窗口类型:注册 RegisterClass()把定义好的窗口属性向系统进行登记。RegisterClass()函数原型为:BOOL RegisterClass(WNDCLASSVisual C+程序设计9 创建窗口:程序使用 API函数 CreateWindow()来创建窗口。创建窗口成功之后,函数返回窗口的句柄,如果应用函数使用该窗口,该句柄应保存在实现 dingy的句柄变量中。 显示窗口:调用 CreateWindow()函数在内存中创建窗口之后,还应用如下两个函数,将窗口显示在计算机显示屏上。BOOL UpdateWindow(HWND hWnd, /窗口句
28、柄Int nCmdShow /窗口的显示方法);和BOOL UpdateWindow(HWND hWnd /窗口句柄); 消息循环:窗口一旦创建并显示,应用程序的初始化及告完工,随后便是程序的消息循环部分。while(GetMessage(DispatchMessage( /把消息派送给系统4.1.2 MFC应用程序主函数MFC把主函数 WinMain函数封装起来,隐藏在应用程序的基本框架内部,在应用程序启动时会调用 WinMain函数完成注册注册窗口等功能。在运行用户的应用程序时,程序的首要框架首先取得控制权,做一些程序的初始化工作。然后构造应用程序类的对象,每一个 MFC程序都必须有且只有
29、一个有CWinApp派生的类对象。当创建完所有的的静态和全局对象后,调用入口函数 WinMain。WinMain 函数首先获得指向应用程序类对象的指针;然后进行初始化工作;接着调用应用程序类的 Run函数,运行程序的消息循环,完成函数功能;最后调用应用程序类的 ExitInstance函数结束程序,删除注册的窗口,释放内存等。MFC程序运行的流程图见图 3。Visual C+程序设计10WinMain()InitInstance()Run()ExitInstance()调用调用调用图 3 MFC程序运行流程图在 MFC程序代码头文件中共有 5个头文件类型:1)FirstMFC.h,FirstM
30、FC.cpp:用户程序的应用类CFirstMFC的头文件和源代码文件,该类由 CWinApp类派生;2)FirstMFCDoc.h,FirstMFCDoc.cpp:用户程序的文件档 CFirstMFCDoc的头文件和源代码文件,该类由 CDocument类派生;3)FirstMFCView.h,FirstMFCView.cpp:用户程序的视图档 CFirstMFC的头文件和源代码文件,该类由CView类派生;4)MainFrm.h,MainFrmcpo:用户程序的主框架窗口类 CMainFrm的头文件和源代码文件;5)ChildFrm.h,ChildFrm.cpp:用户程序的主框架窗口类 CC
31、hildFrm的头文件和源代码文件。4.2程序资源分离4.2.1 Win32程序资源分离在 Win32应用程序中,向菜单、对话框、位图、光标等可视的对象都被从代码中分离出来,这些资源都放在资源文件中资源文件中,资源编译器编译这些并将他们存储在应用程序中,这样大大简化了用户界面的设计。另外,Windows 使用一个称之为句柄的标识符来引用其环境中的每一个对象,比如窗口、内存块、文件、光标、位图等等。句柄是非常方便的数字标识符,用于标识系统已经分配给Windows应用程序的资源。4.2.2 MFC程序资源分离MFC提供了文档/视图模型以实现数据和现实的分离。文档类(Dcument)用来维护、管理数
32、据,包括数据的读取、存储与修改;视图类(View)用来接收显示数据,将这些数据交给文档类来处理。在文档/视图结构中,MFC 文档对象将数据读入或写入永久存储区,并提供数据驻留位置的接口。而一个视图对象可以管理数据显示,包括在窗口中显示数据。编辑数据等。MFC 可以利用文档/视图结构使用一个单独的视图对象表示每个数据视图,还可以使用文档对象同时更新所有试图。MFC 文档/视图将数据结构的存储与维护同其是分开的,图 4显示了文档与视图的关系。Visual C+程序设计11文档视图当前可见的文档视图图 4 文档与视图的关系文档/视图结构类的各自主要作用:1)文档用于管理应用程序的数据;2)视图的主要
33、作用是以图形方式显示文档数据,以及接收用户的输入并将其解释为对文档的操作;3)MFC 框架使用框架窗口来包含视图,框架窗口提供了用于环绕视图的可见框架(菜单、最小化和最大化窗口等),使用窗口框架类管理框架,使用视图类管理框架中的视图,用户与文档之间的交互操作发生在视图的客户区内,而不是框架窗口的客户区内;4)框架使用了两个文档模板类用于管理创建文档及关联的视图和框架窗口的复杂过程,由应用程序对象创建文档模板,由文件模板创建文档和框架窗口,而由框架窗口创建文档的对应视图。5. 消息机制的架构5.1 MFC消息管理机制 标准的 Windows消息:所有以 WM_为前缀的消息都是标准的 Window
34、s消(WM_COMMAND 消息除外),如 WM_PAINT、WM_QUIT 等,这些消息通常含有用于确定如何对消息进行处理的一些参数。标准的Windows 消息一般由窗口对象和视图对象进行处理。 控件消息:使用唯一 ID号来进行标识,使用控件类来操纵。例如,当用户对编辑框中的文本进行修改时,编辑框将发送给父窗口一条包含控件通知码 EN_CHANGE的 WM_COMMAND消息。窗口的消息处理函数将以某种适当的方式对通知消息作出响应,如检索编辑框中的文本。与其他标准的Windows消息一样,控件消息也是由窗口对象和视图对象进行处理。 命令消息:命令消息主要包括由用户界面对象发送的 ON_COM
35、MAND消息,用户界面对象是指菜单、工具栏、快捷键等。它和控件消息的区别在于:控件消息只能由特定控件向 Windows系统传送,Visual C+程序设计12而命令消息是由用户界面发送的,它可以被更多的对象处理。在文档对象、视图对象、窗体对象、控件对象中都能处理这种消息。5.2消息处理程序首先,定义消息 ID:#define WM_MY_MESSAGE (WM_USER+100) /定义自已的消息;然后,定义消息处理函数: afx_msg LRESULT OnMyMessage(WPARAM wParam,LPARAM lParam);接着,建立消息和消息处理函数之间的映射:ON_MESSAG
36、E(WM_MY_MESSAGE,CtestMessageDlg:OnMyMessage);最后,编写消息处理函数:LRESULT CtestMessageDlg:OnMyMessage(WPARAMwParam, LPARAM lParam)/上述代码为消息处理函数的具体实现5.2.1消息循环函数 WindowProc处理 MFC默认的系统消息,用户可以自定义新的消息及消息响应函数。消息处理程序 WindowProc主要完成对分发来的信息的处理工作。函数 WindowProc的定义如下:LRESULT CWnd:WindowProc(UINT message,WPARAM wparam,LPA
37、RAM lparam)switch(message)case.: break;case.: break;default.: break;MFC应用程序消息循环中存在空闲处理机制,即应用程序在没有消息可以处理时,进行空闲处理,等待消息的到来。在处理完一个消息或进入消息循环时,如果消息队列中没有消息要处理,则应用程序执行一次空闲处理。空闲处理由函数 OnIdle完成,其原型为 BOOL OnIdle(LONG lCout)。参数的含义是当空闲处理周期已经完成了多少次 OnIdle调用后,空闲处理函数第一次调用时,该参数设为 1,此后每调用一次加1.返回值表示当前空闲处理周期是否继续调用函数 OnI
38、dle,返回 TRUE表示仍需要执行空闲处理,返回FASLEA则表示消息队列中有消息要处理,当前的空闲处理周期结束后不再执行空闲处理。5.2.2消息的发送Visual C+程序设计13 函数 SendMessage():用于向一个或多个窗口传送消息,该函数将调用目标窗口的窗口函数,直到目标窗口处理完收到的息,该函数才返回。 函数 PostMessage():用于向一个或多个窗口传送消息,它把消息放在窗口创建的线程的消息队列中,然后不等消息处理完就返回。 函数 SendDlgItemMessage():用于向对话框中指定的控件发送消息,直到目标控件处理完收到的消息,该函数才返回。5.2.3消息映
39、射MFC库提供了自动处理功能。MFC 的框架结构通过消息映射机制,将 Windows消息直接映射到一个成员函数进行处理,简化了消息的处理方式,即 MFC提供的消息处理机制使得消息的处理更加容易。MFC采用了消息映射(message map)的机制来处理消息。这种消息机制包括一组消息映射宏,一条消息映射宏把一个 windows消息和其消息处理函数联接起来:BEGIN_MESSAGE_MAP(CLessonView, CView)/ 标准打印命令ON_COMMAND(ID_FILE_PRINT, Visual C+程序设计14在运行程序时,这些通过 DECLARE_MESSAGE_MAP( )宏命
40、令加入的成员能使 MFC确定是否给定的类可以处理特定的消息。并且,如果可能的话,还可以获取消息处理函数的地址。当一个消息到达时,如果预期的类中没有相应的消息处理函数,MFC 就检查基类的消息映射,直到找到能处理该消息的类,如果所有的类都不处理这个消息,那么这个消息就发送给函数 DefWindowProc进行处理。 在声明了类对消息的处理后,还必须建立具体的消息和类成员函数之间的连接。宏命令的参数分别标识消息映射的类和其基类。MFC 需要知道进行消息映射的类的基类,这样它才能成功地传递未处理的消息。消息输入项宏命令用来标识类将在 BEGIN_MESSAGE_MAP()和END_MESSAGE_M
41、AP()之间处理的消息。示例程序中只指定类 CMainWnd处理消息 ON_WM_PAINT。每一个消息输入项都将向_messageEntries 数组中添加一个数组元素。调用宏命令 END_MESSAGE_MAP()表示数组_messageEntries的结束。5.3消息处理程序5.3.1 Win32的一个特殊数据结构句柄Win32使用的一个唯一的整数值,是 4字节长的数值,用于标识应用程序中不同的对象和同类对象中不同的实例。在 Win32应用程序中,存在着诸如窗口、按钮、图标、滚动条等复杂的程序对象和实例。为了在程序中分别和使用它们,必须对它们进行标识。不同 Win32对象的句柄具有不同的
42、类型。5.3.2窗口函数Win32应用程序,必须有一个“窗口函数”来处理各种消息,它是完成用户任务的核心,也是需要程序员编写大量代码的地方。该函数的定义为:LRESULT CALLBACK WndProc(HWND hwnd, /派送消息的窗口句柄UINT message, /系统传递来的消息标识WPARAM wParam, /消息的附加参数(32 位)LPARAM lparam /消息的附加参数(32 位))在主函数中定义窗口类型是,必须把这个窗口函数的名称赋给 WNDCLASS结构的域 lpfnWndProc。5.3.3消息循环系统为每一个应用程序都建立了一个叫做消息队列的存储空间,在程序
43、的运行过程中如果发生了一个事件,Windows 就会把这个时间所对应的消息送入消息列队等待使用。应用程序可以通过调用Windows提供的 API函数 GetMessage()从消息列队中获取消息。并利用 GetMessage()函数的返回值(当获取消息时,该函数返回 TRUE,否则返回 FALSE)组织一个循环,从而不断从消息队列获取消息,一旦获取了一个消息,就把这个消息发送给系统。在 Windows应用程序中,消息循环的代码如下:Visual C+程序设计15while(GetMessage(DispatchMessage( /把消息派送给系统函数 TranslateMessage()用来把
44、键盘消息转化为字符信息,当函数 DispatchMessage()把消息派送给系统后,系统会根据消息的 hwnd找到应该接受消息的程序窗口并根据窗口提供信息,以消息为参数来调用一个用户编写的“窗口函数”的函数,以消息中的消息标识 message为依据查找并执行该消息所对应的程序段,对消息进行处理。5.3.4消息的传输在 Windows中,从消息的传递途径上来看,消息大体上分为两种:一种是先把消息送达消息列队,然后由应用程序的消息循环通过函数 DispatchMessage()获取并通过系统发送给窗口,这类型消息叫做列队消息,鼠标和键盘消息问列对消息;另一种消息则不经过消息列队而直接送到窗口,这
45、类型消息叫做非列队消息,系统事件产生的消息一般为非列队消息。Win32系统把用户应用程序分割成两部分:一个是以消息循环为主的获取和发送消息的部分;另一个是专门处理消息的窗口函数部分。鼠标、键盘等事件事件转化为消息系统消息列队进程消息对列窗口消息应用程序的信息循环while(GetMessage)TranslateMessage(DispatchMessage( 应用程序用于处理消息的窗口进程非队列消息图 5 事件及其消息的传递过程Visual C+程序设计165.4.5消息处理函数Win32应用程序在某种意义上是面对对象的,用户采用“选择对象-操作对象”的方式进行工作。Win32应用程序采取基
46、于事件的消息驱动运行机制,即Win32应用程序通过相应Windows消息来处理事件。事件是系统产生的动作,事件通过消息进行描述和标识。事件驱动是程序设计围绕事件或消息产生驱动运行处理函数。消息是描述事件发生的信息。在 window系统中,程序的执行顺序完全取决于时间的发生顺序。这就使得程序的运行不是由事件的顺序来控制,而是由事件的发生来控制。时间的发生是随机的、不确定的,这就允许了用户用各种合理的顺序来安排程序的流程。这种面向用户的程序设计,更多考虑了用户可能的各种操作,程序员可以有针对性地设计相应的处理程序。事件的驱动模式是一种“被动”的程序设计模型,程序一开始运行就处于等待用户输入的状态,
47、取得事件后作出相应反应,处理完毕又返回等待时间的状态。 Win32 应用程序是按照“事件消息处理”的运行机制。当有某个事件(如单击鼠标、键盘输入和执行菜单命令)等发生时,Win32 会根据具体的事件产生相对应的消息,并发送到指定应用程序的消息队列,应用程序从消息队列中取出消息,并根据不同的消息进行处理。接受并处理消息的主角就是窗口。每一个窗口都应该有一个处理消息的函数,就是消息处理函数。6 MFC与 Win32程序设计优缺点最初,面向对象程序设计的提出是为了解决传统程序设计方法结构化程序设计所不能解决的代码重复问题。结构化程序设计依程序功能为中心,应用程序由如干功能模块组成,随着用户需求的变化
48、和软、硬件技术的发展,结构化的应用程序就显得缺乏灵活性和稳定性,代码重用性很低。面向对象程序设计以数据为中心,采用对象来描述问题,使问题的共性得以抽象,从而大大提高了代码的可重用性。具有相同操作和属性的对象集合被称为类,不同的操作和属性可以通过不同的类来表示。直接针对 Windows API进行程序设计有一定难度,且工作量较大。MFC 类库的一个最重要的特点就是实现了对 Windows API的封装,使得 Windows应用程序开发更加建明快捷。此外,MFC 应用程序框架,为 Windows应用程序停工了标准化的结构,用户只需向框架内添加实现特殊功能的代码,而不必担心框架程序的编写。MFC 的
49、这一特性在为用户带来巨大方便的同时,也使基于 MFC的 Windows应用程序更为清晰,代码更为高效。MFC作为微软基础类库,是用来编写 Windows应用程序的 C+类集,它具备了面向对象程序设计的主要特征:抽象、继承和封装。MFC 的重要特征之一就是它实现了对 Windows API的封装,从而避免了对复杂的 Windows API函数的直接操作,大大简化了应用程序的编写。此外,MFC 还实现了对应用程序概念、COM/OLE 特性、ODBC 功能的封装。MFC最大的优点在于它是 Win32应用程序开发的宏观框架体系。MFC 通过对应用程序概念等一系列的封装,形成了应用程序开发的模板,如单文件应用程序的模板、多文件应用程序的模板扩展 DLL应用程序的模板、OLE/ACTIVEX 应用程序的模板等。这些模板都是基于文档视图结构,每一个模板都包含Visua