MFC编程概述.doc_第1页
MFC编程概述.doc_第2页
MFC编程概述.doc_第3页
MFC编程概述.doc_第4页
MFC编程概述.doc_第5页
已阅读5页,还剩34页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第3章 MFC应用程序概述精讲Microsoft Windows是微软公司推出的一个应用于微机上的具有图形用户界面的多任务和多窗口的操作系统。Windows应用程序也称为窗口应用程序,所有的窗口应用程序都有着相同的窗口风格和菜单结构,用户界面友好,方便用户操作。本章从剖析窗口应用程序的基本结构入手,继而介绍使用MFC类库开发的应用程序框架结构,并介绍窗口应用程序运行的核心机制消息映射。学习了本章,你将对MFC应用程序框架结构和运行机制有个整体的了解,为后面进入窗口应用程序开发打下良好的基础。3.1 窗口应用程序概述窗口应用程序的开发一般采用可视化的面向对象的开发,可选择的窗口应用程序开发语言有Visual C+、Visual Basic、Visual Java、Dephi等等。无论采用哪一种开发语言,首先要了解窗口应用程序的基本机制。3.1.1 窗口编程基础窗口应用程序运行于Windows操作系统,Windows操作系统是一个多任务操作系统,因此窗口应用程序的组成,支持技术,基本运行机制等与DOS应用程序有着本质的区别。在学习开发窗口应用程序之前,先要对窗口应用程序有一个概念上的了解。1 窗口窗口是应用程序与用户进行交互的界面,应用程序通过窗口传递信息给用户,同样用户通过窗口输入数据,发布命令给应用程序。Windows界面包含了丰富的标准用户界面元素,包括窗口、图标、菜单、滚动条、对话框、控件和消息框等。用户使用这些界面元素可以方便的与应用程序进行交互,一个典型的窗口外观如图3-1所示。垂直滚动条控制菜单栏标题栏菜单栏关闭按钮最小化按钮最大化按钮水平滚动条窗口边界客户区图3-1 Windows应用程序窗口组成 在Windows编程中,各种窗口、菜单、按钮、对话框及程序模块等Windows的规范部件是按“对象”来组织的。为了提高开发窗口应用程序的效率,微软公司为用户提供了大量能创建上述标准元素的API函数和C+类,并且以Windows API函数库和C+类库的形式提供给用户,以充分满足构成应用程序操作界面的需要。因此,要编写窗口应用程序必须了解这些标准对象的属性及方法,这样程序员的大量工作简化为创建对象和为对象属性赋值。标准对象具有标准的形态及标准的操作方法,并且能够对鼠标或键盘操作产生标准的消息响应。在后面的章节中将会陆续介绍上述窗口界面元素的创建原理和创建方法。一个窗口应用程序可能包含一个或多个窗口,应用程序的运行过程即是窗口内部、窗口与窗口之间、窗口与系统之间进行数据处理与数据交换的过程。2 消息和消息队列窗口应用程序是利用消息(Message)与其它窗口应用程序和操作系统进行信息交换的。消息的作用是通知一个应用程序某个确定的事件的产生,应用程序会对该事件产生响应,响应的方式已预先在应用程序中定义,即编写了相应的消息处理代码。例如当按下鼠标左键时,系统会产生WM_LBUTTONDOWN消息,并通知应用程序窗口,应用程序接到该消息后,会检查是否已定义消息处理函数并作出响应。Windows操作系统内核基本元件USER为所有的用户界面元素提供支持,它用于接收和管理所有输入消息、系统消息,并把它们发送给相应应用程序的消息队列。消息队列是一个系统定义的内存块,用于临时存储消息,或是把消息直接发给窗口过程。每个应用程序都维护着自己的消息队列,并从中取出消息,利用窗口函数进行处理。如图3-2所示。应用程序1窗口函数WndProc消息映射默认窗口函数DefWndowProcApp1消息队列 App2消息队列 App3消息队列 系统队列输入消息系统消息postMessageSendMessage图3-2 消息驱动模型窗口应用程序接受系统队列传递过来的消息的步骤如下:(1) 每个窗口应用程序都有一个WinMain()函数,在该函数中会定义一个窗口句柄,当窗口应用程序启动时,会使用窗口句柄注册,操作系统使用窗口句柄与窗口应用程序通信。(2) 窗口应用程序创建一个或多个窗口,每一个窗口都有一个窗口处理函数(WndProc),负责窗口显示和响应用户输入。(3) 消息映射(Message Loop)负责从消息队列中取消息,并送回窗口,由窗口处理函数选择合适的消息处理函数响应消息。若窗口处理函数中没有给出该消息的处理代码,将由DefWindowProc函数进行默认处理。消息机制是窗口应用程序运行的核心工作机制,消息往往用一个如下的结构体MSG来表示,其定义如下:typedef struct tagMSG HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt;MSG;其中结构成员说明如下:(1) hwnd该消息所在的窗口句柄,若此参数为null,则可检索所有驻留在消息队列中的消息。(2) message消息值,每个Windows消息都有一个消息值,该值由Windows.h头文件中的宏定义来标识。(3) wParam和lParam包含有关消息的附加信息,它随消息的不同而不同。(4) time指定消息送至队列的时间。(5) pt指定消息发送时屏幕光标的位置,其数据类型POINT也是一个结构体,其定义如下:typedef struct tagPOINT LONG x; LONG y; POINT;Windows应用程序的消息来源有以下4种:(1) 输入消息由键盘和鼠标操作产生输入消息。这一类消息首先放在系统消息队列中,然后由Windows操作系统将它们送入应用程序消息队列中,由应用程序来处理消息。(2) 控件消息用户操作窗口的控件对象时产生控件消息, 例如当用户在列表框中改动当前选择或改变了复选框的状态时就会发出控件消息。这类消息一般不进入应用程序消息队列,而是直接发送到控件对象所属的对话框窗口。(3) 系统消息对程序化的事件或系统时钟中断做出反映。一些系统消息,象DDE消息(动态数据交换消息)要通过Windows的系统消息队列,而另一些系统消息则不通过系统消息队列,而直接送入应用程序的消息队列,如创建窗口消息。(4) 用户消息这是程序员自己定义并在应用程序中主动发出的,一般由应用程序的某一部分内部处理。3 事件驱动的程序设计Windows操作系统下的窗口应用程序采用事件驱动的程序设计,与DOS操作系统下的面向过程的程序设计有着明显的不同。在DOS操作系统下,用户在DOS提示符后输入一行命令及参数,启动应用程序并按程序指定运行。一个程序是一系列预先定义好的操作序列的集合。程序直接控制程序事件和过程的顺序,并按照某种不可改变的模式进行工作。在窗口应用程序下,用户首先启动应用程序,然后窗口等待用户通过对图形界面上的元素的操作,传递信息和命令,如选择一个菜单项或者单击一个按钮。窗口应用程序不是按事先安排好的顺序来执行的,而是由事件的发生来控制逻辑。事件的发生是随机的、不确定的,这样就允许用户按各种合理的顺序来安排程序的流程。例如,有这样一个简单的应用程序,程序的功能是计算体操全能比赛项目运动成绩管理,体操全能包括四个项目。在一个过程驱动的程序中,要按照如下步骤完成应用程序功能的实现。(1) 输入第一项运动员的成绩。(2) 输入第二项运动员的成绩。(3) 输入第三项运动员的成绩。(4) 输入第四项运动员的成绩。(5) 计算每个运动员的总分。(6) 按总分排名。在过程驱动的程序中,程序执行的顺序是确定的,如图3-3所示。开始输入第一项运动员的成绩输入第二项运动员的成绩输入第三项运动员的成绩输入第四项运动员的成绩计算每个运动员的总分按总分排名结束图3-3 过程驱动程序流程示例在这种过程驱动的程序中,首先按事先安排好的顺序把所有的成绩输入,然后再计算每一个运动员的总分,再进行成绩排名。事件驱动的程序的逻辑顺序是按事件的产生而决定的,事件的产生不是预先定义的,有着随机性。图3-4给出了事件驱动程序的流程示意图。开始输入第一项某运动员的成绩输入第二项某运动员的成绩输入第三项某运动员的成绩输入第四项某运动员的成绩计算每个运动员的总分按总分排名结束消息循环 图3-4 事件驱动程序流程示例事件驱动的应用程序启动后,每一个事件的发生将在对应的消息队列中放置一条消息,这样基于事件产生的输入没有固定的顺序,用户可以随机选取,以任何合理的顺序来输入数据。程序开始运行时,处于等待用户输入事件状态,然后取得消息并作出相应反应,处理完毕又返回并处于等待事件状态。在这种处理逻辑中,用户可以按需要进入不同的事件处理,例如,可以录入任意一个比赛项目,某位运动员的成绩,而不需要考虑录入顺序,随时计算运动员当前的总分和排名。体操比赛通常是几个项目同时进行,在比赛进行中,可以实时地输入运动员的得分,随时反映每个运动员的当前得分和当前总分排名情况。4 资源管理资源可分为用户自定义资源和系统资源两种。用户自定义资源是指窗口可视元素的映像,即在前面所提及的窗口所包含的标准元素。例如菜单、对话框、工具栏等,是由每一个应用程序各自定义的。系统资源是由系统提供给各个应用程序共享的,常见的系统资源包括:设备上下文,画刷、画笔、字体、通信端口等。由于Windows操作系统是一个多任务的操作系统,多个应用程序要共享系统资源,而不能象DOS程序独占系统的全部资源。系统资源是有限的,窗口应用程序使用资源的模式为:请求资源,使用资源,释放资源。如果系统资源在使用后不能得到及时的释放,会影响其它应用程序使用资源,最终造成死机。系统资源以句柄来标识,使用系统资源要通过Windows API函数来实现安全访问。在窗口程序设计中,用户自定义资源与程序是分开定义的,在Develop Studio中提供了资源管理器用于用户自定义资源的创建、修改和维护。用户可以使用资源管理器提供的模板来设计资源,保存在资源文件中,资源文件通常以.RC为后缀名。每一个用户自定义资源都有唯一的ID标识,可以用一个自定义的整数或一个名称来表示。资源编译程序最终会将资源编译为应用程序所能读取的对象的二进制映像和具体的数据结构,并存放于应用程序的可执行文件中或动态连接库中,这样减轻了程序设计中定义和管理资源的复杂性。3.1.2 Windows应用程序组成在这一节中将分析一个简单的Win32窗口应用程序,MFC应用程序是建立在Win32应用程序设计的基础上的,这将帮助更好地理解一个MFC应用程序是如何初始化的,窗口是如何创建的,消息是如何处理的。所有的窗口应用程序必须包含两个基本函数:(1) 应用程序主函数WinMain()WinMain函数定义了窗口句柄,创建初始化窗口并启动一个消息循环。(2) 窗口处理函数WinProc()WinProc函数处理所有从操作系统传递到窗口的消息。每一个窗口,无论是简单的或复杂的,都要有一个窗口处理函数。【例3-1】创建一个简单的窗口应用程序示例。本例的目的在于说明创建Windows应用程序的方法及过程。(1) 在VC集成开发平台,执行菜单“File”下的菜单命令“New”,打开“New”对话框。(2) 在“New”对话框中的“Project”标签页中选择“Win32 Application”,在右边输入工程名为:Exam3_1,并确定工程文件保存位置,单击“OK”按钮。(3) 在随后的向导窗口Win32 Application-step 1of 1中,选择“An empty project”,单击“Finish”按钮。(4) 在出现的“New Project Information”对话框中,单击“OK”按钮,完成工程的创建,并回到集成开发平台。(5) 再执行菜单“File”下的菜单命令“New”,添加一个新的C源文件(*.cpp),程序名为Exam3_1。(6) 按程序清单3-1中的代码实现Exam3_1.cpp文件。(7) 编译运行。 程序清单3-1:创建一个简单的Windows窗口程序代码/包含应用程序中所需的数据类型和数据结构的定义#include/窗口函数说明LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); /- 以下初始化窗口类 -int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) HWND hwnd ; MSG Msg ; WNDCLASS wc; char szApplicationName= Exam3_1Window;/窗口标题名/定义窗口类wc.style=CS_HREDRAW|CS_VREDRAW; /定义窗口类型为当窗口大小变化时窗口重画wc.lpfnWndProc=WndProc;/定义窗口处理函数wc.cbClsExtra=0;/窗口类无扩展wc.cbWndExtra=0;/窗口实例无扩展wc.hInstance=hInstance;/当前实例句柄wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);/窗口的最小化图标为缺省图标 wc.hCursor=LoadCursor(NULL,IDC_ARROW) ;/窗口采用箭头光标wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);/窗口背景为白色wc.lpszMenuName=NULL;/窗口中无菜单wc.lpszClassName= szApplicationName;/定义应用程序标题/-注册窗口类-RegisterClass( &wc);/- 创建窗口 - hwnd=CreateWindow(szApplicationName,/窗口类名szApplicationName,/窗口的标题名WS_OVERLAPPEDWINDOW,/窗口的风格CW_USEDEFAULT,CW_USEDEFAULT,/窗口左上角坐标为缺省值CW_USEDEFAULT,CW_USEDEFAULT,/窗口的高和宽为缺省值NULL,/此窗口无父窗口NULL,/此窗口无主菜单hInstance,/创建此窗口的应用程序的当前句柄NULL );/- 显示窗口 -ShowWindow( hwnd, nCmdShow) ;/- 绘制用户区 -UpdateWindow(hwnd);/- 消 息 循 环 - while( GetMessage(&Msg, NULL, 0, 0)TranslateMessage( &Msg) ;DispatchMessage( &Msg) ;return Msg.wParam;/消息循环结束即程序终止时将信息返回系统/-窗口函数-LRESULT CALLBACK WndProc( HWND hwnd, UINT message,WPARAM wParam,LPARAM lParam) switch(message) case WM_DESTROY:PostQuitMessage(0);/ 调用PostQuitMessage发出WM_QUIT消息default:/缺省时采用系统消息缺省处理函数return DefWindowProc(hwnd,message,wParam,lParam); return 0;上述程序的运行结果如图所示:图3-5 程序运行结果图1 WinMain函数和C语言中的main()函数一样,Windows程序是从WinMain()函数开始的,并随着WinMain函数的结束而结束的。WinMain()函数是在WINBASE.H中定义的,定义如下:int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);参数说明如下:(1) hInstance系统分配的窗口所属的应用程序的实例句柄,标识当前进程的实例,它实际上是进程所占据的地址空间的首地址,这个实例句柄是程序的唯一标识。(2) hPrevInstance用做检查是否有多个程序实例运行,这是16位Window的残留物,在Win32应用程序中,这个参数始终为NULL。(3) lpCmdLine是一个指向字符串的指针,用来保存运行程序时的命令行参数,这同main()函数中的argv参数的作用类似。(4) nCmdShow用来指明应用程序的主窗口的显示方式(最大化显示,最小化显示,一般化显示)。该参数经常被ShowWindow()函数作为显示窗口的参数。WinMain()函数的作用是完成以下三个任务:注册窗口类;创建并初始化窗口;创建消息循环。 (1) 注册窗口类每个窗口都包含着一些基本的属性,如:窗口边框、窗口标题栏文字、窗口大小和位置、鼠标、背景色、处理窗口消息函数的名称等等。注册的过程就是将这些属性告诉系统。窗口应用程序使用结构体WNDCLASS描述窗口类型,它描述了窗口的样式、窗口消息处理函数、程序句柄、图标、光标、背景刷、菜单以及描述本窗口类型的结构的名称。首先使用数据结构WNDCLASS定义窗口的各个属性,再使用Windows 的API函数RegisterClass()注册窗口类。结构体WNDCLASS定义如下:typedef struct tagWNDCLASSUNIT style;/指定窗口格局的整型数, WNDPROC lpfnWndProc;/负责控制窗口、处理窗口消息的窗口函数,int cbClsExtra;/为指定这个窗口类别结构额外分配的字节数,一般设为0。int cbWndExtra;/为指定这个窗口类别中所有窗口结构额外分配的字节数,一般设为0。HANDLE hInstance;/ 标志要创建的窗口所属应用程序的句柄。HICON hIcon;/ 指定窗口的最小化图标句柄。HCURSOR hCursor;/ 窗口中所使用的光标的句柄。HBRUSH hbrBackground;/ 用来画窗口背景的画刷的句柄。LPCWSTR lpszMenuName;/ 标志窗口中的菜单资源名字的字符串。LPCWSTR lpszClassName;/ 标志该窗口类别的名字的字符串。 WNDCLASS;RegisterClass()函数接收的是一个WNDCLASS结构的指针。如果注册成功,RegisterClass()返回TRUE,否则返回FALSE。只有注册成功后,才能创建窗口。(2) 创建并初始化窗口如果窗口类注册成功,下一步,便可以使用该窗口类创建窗口。CreateWindow()函数用于创建窗口,该函数进一步定义了窗口的名称,位置,尺寸等数据。如果创建成功,则返回一个系统分配的窗口句柄,否则返回0。CreateWindow()函数定义如下:HWND CreateWindow(LPCTSTR lpszClassName, 窗口类名 LPCTSTR lpszTitle, 窗口标题名 DWORD dwStyle, 创建窗口的样式 int x,y, 窗口左上角坐标 int nWidth,nHeight, 窗口宽度和度高 HWND hwndParent, 该窗口的父窗口句柄 HWENU hMenu, 窗口主菜单句柄 HINSTANCE hInstance, 创建窗口的应用程序当前句柄 LPVOID lpParam 指向一个传递给窗口的参数值的指针 );窗口创建成功后并没有显示出来,还需要调用ShowWindow()和UpdateWindow()两个函数来显示窗口,这两个函数定义如下:ShowWindow (hwnd, nCmdShow );UpdateWindow (hwnd );ShowWindow()函数的作用是显示或隐藏窗口,第一个参数是要显示的窗口的句柄,第二个参数表示窗口的显示样式,如SW_SHOW表示正常显示,SW_HIDE表示隐藏。UpdateWindow()函数的作用是更新当前窗口显示。(3) 创建消息循环WinMain()函数最后使用while语句创建一个消息循环,负责从消息队列中获取消息,并派送消息到相应的处理位置。最简单的消息循环由TranslateMessage()和DispatchMessage()函数组成,格式如下:while (GetMessage (&Msg,NULL,0,0)TranslateMessage(&Msg); DispatchMessage(&Msg); GetMessage()函数负责检查应用程序的消息队列,一旦发现队列中有消息,便取出一条消息,把它复制到MSG结构体变量中,同时该函数返回TRUE。TranslateMessage()函数的作用是将来自键盘的命令翻译为消息的ID字符表示。DispatchMessage()函数的作用是把每个消息分发给相应的窗口函数。当检索到WM_QUIT消息时,程序结束循环并退出。2 窗口处理函数注册窗口类的一个主要目的就是将一个窗口和一个窗口处理函数联系起来,窗口处理函数决定窗口在它的客户区中显示什么,和窗口如何响应用户输入。窗口处理函数能够按程序员预先定义的代码处理消息,如果程序员没有对该消息的处理作定义,则把此消息交给默认窗口处理函数DefWindowProc()处理。函数DefWindowProc()是系统默认的处理过程,以保证所有发送到该窗口的消息均得到处理。窗口函数定义如下:LRESULT CALLBACK WndProc( HWND hwnd,UNIT message,WPARAM wParam,LPARAM lParam)说明如下:(1) LRESULT表示函数返回值为长整数,由系统使用。(2) CALLBACK表示该函数是回调函数,由系统调用。(3) hwnd该参数是接收消息的窗口句柄,它和CreateWindow()函数的返回值相同。(4) message该参数是用来标识该消息的数字。(5) wParam和 lParam 两个参数是32位的消息参数,用来提供消息的附加信息。在例3-1中窗口处理函数的名称为WndProc,这个名称可以由用户自己在窗口类的lpfnWndProc属性中指定,例如可改为MyWndProc。在窗口函数中,根据接收的消息信息(message,wParam和lParam)进行判断,然后分门别类地进行处理。窗口函数中使用switch语句定义对应用程序接收到的不同消息的响应,包含了对各种可能接收到的消息的处理过程。每一条case语句对应一种消息,当应用程序接收到一个消息时,相应的case语句被激活并执行相应的响应程序模块。程序员可以在switch语句中增加对各种消息的处理代码。WM_DESTROY消息是关闭窗口时发出的,处理方法是调用函数PostQuitMessage() 向应用程序发出WM_QUIT消息,请求退出处理函数。MFC应用程序是建立在窗口应用程序开发模式的基础上的,同样MFC应用程序也有一个WinMain()函数,但程序员不用编写该函数,WinMain()函数由框架提供,当应用程序启动时被自动调用。MFC有一个内部的消息系统处理由类产生的绝大多数消息。当一个消息不能被 MFC所处理,应用程序将它交给默认窗口处理函数DefWindowProc()来处理。3.1.3 应用程序举例【例3-2】分析使用AppWizard生成的Win32窗口程序示例Exam3_2,并对该程序作以下修改:(1) 修改输出文本串“Hello World!”为”Hello VC+!”。(2) 在视图的中央输出文本“starting your VC+ learning !”。(3) 添加一个对话框,并能使用菜单调用这个对话框。分析HelloWorld程序:在第一章的实践2中已描述了使用AppWizard快速生成Win32窗口程序示例的步骤,下面对同样方法生成的Exam3_2程序进行分析:1 WinMain函数程序清单3-2:Exam3_2中的WinMain函数int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) / TODO: Place code here.MSG msg;HACCEL hAccelTable;/ 初始化全局字符串LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadString(hInstance, IDC_EXAM3_2, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance);/注册窗口类句柄/ 初始化应用程序if (!InitInstance (hInstance, nCmdShow) /创建并显示窗口return FALSE; hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_EXAM3_2);/装载快捷键/ 主消息循环while (GetMessage(&msg, NULL, 0, 0) if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg) TranslateMessage(&msg);DispatchMessage(&msg);return msg.wParam;如程序清单3-2所示,WinMain()函数的构成同样包含三个主要过程:(1) 通过MyRegisterClass()函数定义窗口类句柄,并返回RegisterClassEx()函数结果;(2) 通过InitInstance()函数调用CreateWindow()创建窗口,并显示更新窗口;(3) 创建消息循环,接收消息并分发消息。LoadString()函数的作用是加载字符串资源,字符串资源是在字符串表中定义的,如图3-6所示,IDS_APP_TITLE表示应用程序的名称,加载到szTitle数组,IDC_EXAM3_2表示Windows默认类的标识名,加载到szWindowClass数组,在定义窗口和创建窗口的时候调用。 图3-6 HelloWorld中的字符器资源定义2 窗口函数WndProc程序清单3-3:Exam3_2中的WndProc函数和About函数LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)int wmId, wmEvent;PAINTSTRUCT ps;HDC hdc;TCHAR szHelloMAX_LOADSTRING;LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); /分派窗口消息处理switch (message) case WM_COMMAND: /处理菜单消息wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); / Parse the menu selections:switch (wmId)case IDM_ABOUT: DialogBox (hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); break;case IDM_EXIT: DestroyWindow(hWnd); break;default: return DefWindowProc(hWnd, message, wParam, lParam);break;case WM_PAINT: /处理窗口重绘消息hdc = BeginPaint(hWnd, &ps);/ TODO: Add any drawing code here.RECT rt;GetClientRect(hWnd, &rt);DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);EndPaint(hWnd, &ps);break;case WM_DESTROY: /处理应用程序退出消息PostQuitMessage(0);break;default: / 启动默认窗口处理函数return DefWindowProc(hWnd, message, wParam, lParam); return 0;/About对话框的消息处理函数LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)switch (message)case WM_INITDIALOG:return TRUE;case WM_COMMAND:if (LOWORD(wParam) = IDOK | LOWORD(wParam) = IDCANCEL) EndDialog(hDlg, LOWORD(wParam);return TRUE;break; return FALSE;如程序清单3-3所示,窗口函数WndProc()是处理各种消息,在这个例程中处理三类消息:(1) WM_COMMANDWM_COMMAND是操作菜单项、加速键或工具按钮发出的命令消息,其中窗口消息包包含的WParam字段的低16位为命令ID,变量wmId获得命令ID后,使用switch语句继续对不同的命令消息进行处理。IDM_EXIT是菜单命令“Exit”的ID,处理方法是调用DestroyWindow()函数了发出WM_DESTROY消息。IDM_ABOUT是菜单命令“About”的ID,处理方法是调用DialogBox()函数,打开对话框窗口。在使用DialogBox()函数时,需要指定对话框资源ID和对话框消息处理函数。在本例中,对话框资源IDD_ABOUTBOX,对话框消息处理函数是About()函数。对话框消息处理函数的构造与窗口函数WndProc()类似,通过一个分情况语句响应不同的消息。在About()函数中对对话框的初始化消息WM_INITDIALOG和命令消息WM_COMMAND进行了处理。对话框运行时,单击“OK”按钮就发出消息IDOK,单击“Cancel”按钮时发出IDCANCEL,系统定义的IDOK和IDCANCEL的消息处理中,都调用了EndDialog()函数关闭对话框窗口。(2) WM_PAINTWM_PAINT是窗口重绘消息,当窗口大小发生变化、移动、滚屏、菜单覆盖视图、鼠标掠过视图等任何使视图显示改变的情况下,都会发出WM_PAINT消息。本例的处理是在调用DrawText()函数在视图的顶部中央输出文本串szHello,szHello的内容是通过LoadString函数装载的字符串资源IDS_HELLO。(3) WM_DESTROY退出应用程序的消息处理,调用PostQuitMessage()函数,结束消息循环,WinMain()函数运行结束。按要求修改示例程序:1 修改输出文本串“Hello World!”为”Hello VC+!”(1) 展开工作区ResourceView面板中的String Table资源,双击打开String Table。(2) 双击IDS_HELLO,弹出String Properties对话框,在Caption中修改字符串的内容,即输入“Hello VC+!”。(3) 重新编译运行程序。 2 在视图的中央输出文本“starting your VC+ learning !”(1) 在FileView面板中展开Source Files文件夹,双击Exam3_2.cpp文件打开,找到WndProc()函数。(2) 在WM_PAINT消息的处理中添加文本输出函数语句如下:DrawText(hdc,starting your VC+ learning!,28,&rt,DT_SINGLELINE|DT_CENTER|DT_VCENTER);(3) 重新编译运行程序。3 添加一个对话框,并能使用菜单调用这个对话框(1) 执行菜单命令Insert-Resource,在弹出的对话框中选择Dialog,单击按钮“New”,系统会添加一个新的对话框资源IDD_DIALOG1到ResourceView面板中的Dialog文件夹中。(2) 双击IDD_DIALOG1打开对话框编辑器窗口,在窗口任意空白处右击鼠标键,在打开的快捷菜单中选择Properties,在弹出的Dialog Properties窗口中的Caption内容修改为“MyDialog”,此即为修改后的对话框的标题栏名称。(3) 在工作区的ResourceView面板中,展开Menu菜单资源,双击IDC_EXAM3_2,打开菜单编辑器窗口,在Help菜单中添加一个菜单项。即双击Help菜单下的空白处,在打开的Menu Item Properties窗口中输入,Caption内容为:MyDialog,ID号定义为:IDM_MYDIALOG。(4) 在WndProc()函数对WM_COMMAND窗口消息的情况处理分支中添加对IDM_MYDIALOG菜单消息的处理代码如下,调用DialogBox打开IDD_DIALOG1对话框:case IDM_MYDIALOG:DialogBox(hInst, (LPCTSTR)IDD_DIALOG1, hWnd, (DLGPROC)Mydialog);break;(5) 在Exam3_2.cpp文件的最后添加对话框消息处理函数Mydialog函数,代码如程序清单3-4所示。程序清单3-4:对话框消息处理函数Mydialog函数LRESULT CALLBACK Mydialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)switch (message)case WM_INITDIALOG:return TRUE;case WM_COMMAND:if (LOWORD(wParam) = IDOK | LOWORD(wParam) = IDCANCEL) EndDialog(hDlg, LOWORD(wParam);return TRUE;break; return FALSE;(6) 在Exam3_2.cpp文件的头部的函数声明处添加函数声明语句如下:LRESULT CALLBACK Mydialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);(7) 重新编译运行程序,执行菜单命令MyDialog,打开自定义的对话框。最后运行效果如图3-7所示。执行菜单命令MyDialog,打开的自定义对话框图3-7例3-2程序运行效果3.2 MFC应用程序框架利用Windows API函数编制Windows应用程序, 程序员需要编写大量的程序代码。而利用MFC编写实现同样功能的程序,则要轻松得多。在第一章中我们学习了使用AppWizard创建一个MFC单文档应用程序,不需要做任何额外的工作,直接运行程序,一个具备常用工具栏、菜单栏、状态栏的标准窗口应用程序就已经出现的屏幕上。 MFC(Microsoft Foundation Class)是由微软编写的一套专门用于Windows编程的C+基础类库,其内容很广泛,功能也相当强大,VC编程基本上都是围绕着MFC类库来进行的,它封装了Windows API的绝大多数功能,通过用户开发Windows应用程序建立了一个非常灵活的应用程序框架。但习惯使用SDK编写窗口应用程序的程序员,初次接触MFC编程时都会有这样困惑:找不到WinMain函数,应用程序如何执行?程序的执行似乎不在程序员的掌握之中。所以如何理解MFC应用程序框架是学习VC的核心任务之一。3.2.1 MFC类简介MFC类库中的各个类支持快速生成面向对象的应用程序,它们之间存在一定的关联,它们的集合构成MFC应用程序框架,如图3-8所示。CObjectCCmdTargetCWinThreadCWinAppCWndCFrameWndCViewCDocument图3-8 MFC类的继承关系CObject是MFC类库的根类。从CObject派生的类都具有以下特点:(1) 在程序运行时,可获得对象的大小、类名、动态创建类的实例。(2) 提供了把对象状态转储给调试机制的能力,类似于判断当前对象的数据成员是否有效。(3) 具有把对象的数据存进文件、或从文件中提取数据重建对象的能力。命令类CCmdTarget:是CObject的子类,它是MFC库中所有具有消息映射属性的基类。它的子类有CWinThread类,CWnd类、CDocument类,从CCmdTarget派生的类在程序运行时,能动态创建对象,并能处理命令消息。应用程序线程支持类CWinThread:MFC支持多线程,所有的应用程序至少有一个线程。CWinThread是所有线程类的基类,封装了操作应用程序的多线程功能。应用程序类CWinApp是CWinThread的子类,封装了初始化、运行、终止应用程序的代码。窗口类CWnd:提供了MFC中所有窗口类的基本功能。从CWnd派生的类可以拥有自己的窗口,并能对它进行控制。框架窗口类CFrameWnd和视图类CView是CWnd类的两个子类,前者提供和维护窗口的边框、菜单栏、工具栏、状态栏,负责显示和搜索用户命令,后者负责为文档提供一个或几个视图。视图的作用是为修改、查询文档等任务提供人机交互的界面。文档类CDocument:负责装载和维护文档。文档包括应用程序的工作成果或环境设置数据等,或是程序需要保存的任何内容。一个MFC应用程序并不直接操作上述类,而是从上述类为基类派生新的类,构建窗口应用程序的基本框架。例如应用程序Exam1_1中的类与这些基类的派生如表3_1所示。表3-1基类与派生类的关系类名称基类说明CExam1_1AppCWinApp应用程序类CMainFrameCFrameWnd窗口框架类CExam1_1DocCDocument文档类CExam1_1ViewCView视图类3.2.2构建窗口应用程序的基本类利用VC+提供的AppWizard,可直接生成MFC应用程序。但无法看到Windows程序结构中的主函数WinMain和窗口函数Wnd

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论