C及Windows可视化程序设计 刘振安著.pptx
《C及Windows可视化程序设计 刘振安著.pptx》由会员分享,可在线阅读,更多相关《C及Windows可视化程序设计 刘振安著.pptx(142页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、本章将介绍如何使用MFC类库编程,并通过一个简单的例子说明MFC的消息处理机制。然后模拟文档/视结构编制一个程序,通过它引入使用向导和文档/视结构的概念,为学习下一章的文档/视结构打下基础。最后给出一个基于对话框风格的实例。第1页/共142页在使用MFC类库编程之前,先来看一个使用全局对象的例子。【例12.1】使用全局对象启动程序运行。/example.h文件#include using namespace std;class CMyApp int x,y,z;public:CMyApp(int a=0,int b=0,int c=0):x(a),y(b),z(c)coutBegin.endl
2、;12.1 一个使用全局对象的程序第2页/共142页void SetNum(int a,int b,int c)x=a;y=b;z=c;int Add()return x+y+z;/example.cpp文件#include example.hCMyApp theApp;/全局对象void main()coutIn main.endl;theApp.SetNum(2,4,6);couttheApp.Add();coutendlGo out.endl;第3页/共142页程序运行输出如下:Begin.In main.12 Go out.程序是先执行“CMyApp theApp;”创建并初始化惟一全
3、局对象theApp,输出信息“Begin.”,然后进入主程序。Visual C+6.0的程序设计方法也是如此,即先建立并初始化惟一的全局对象theApp。图12.1左边的框中给出这个程序的类图及全局变量图,右边是程序的.cpp文件。第4页/共142页图12.1 Object的类图及全局变量第5页/共142页C+类库运用面向对象技术,大大简化了程序的设计工作。Microsoft公司提供的基础类库MFC(Microsoft Foundation Classes)就是一个常被称为Application Framework的大类库,其中包含用来开发Windows下C+应用程序的一组类,封装了大部分的W
4、indows API,大大加速Windows下C/C+程序员的软件设计。12.2 使用MFC编制Win32 Application程序第6页/共142页习惯上分别用Win16 和Win32区别16位和32位Windows程序,Windows API则是泛指两者。由前面的讨论可知,驾驭数以千计的API函数并非易事。MFC则把这些浩繁的API函数逻辑地组织起来,使它们具有面向对象的抽象性、封装性、继承性和多态性等特点。怎样学习MFC类库,各人意见不一。很多人认为:“学习MFC,最重要的一点是要学会抽象地把握问题,不求甚解”。这可能对减轻学习难度、提高兴趣是有帮助的,不过也有一些问题,即很多人成了代
5、码拼凑机、只见树木不见森林。第7页/共142页其实,在学习开始就了解Windows程序的基本运行原理,并了解MFC是怎样与之结合的,能大大加快理解,让人更易于接受MFC,这样学习似慢实快。相反,很多书从头到尾地教读者如何如何做,最后仍旧不知所以。学习MFC要理解MFC的应用程序框架,熟记其类层次结构,并不需要刻意去记忆众多的类及它们的成员函数。第8页/共142页【例12.2】使用MFC类库编制输出“Hello MFC”的程序。文档/视的结构比较复杂,先不让向导(AppWizard)生成代码,仍然用Visual C+6.0集成开发环境生成一个空的Win32应用程序项目SMFC1。建立SMFC1.
6、cpp文件如下:第9页/共142页#include/使用MFC类库需要包含的头文件class CMyWin:public CFrameWnd public:CMyWin()protected:afx_msg void OnPaint();DECLARE_MESSAGE_MAP()/声明宏;/使用消息宏BEGIN_MESSAGE_MAP(CMyWin,CFrameWnd)ON_WM_PAINT()END_MESSAGE_MAP()第10页/共142页void CMyWinOnPaint()CString str=Hello,MFC!;/设置输出窗口的 /字符串内容CRect rect(240,1
7、00,340,200);CPaintDC dc(this);dc.DrawText(str,&rect,DT_CENTER);class CMyApp:public CWinApp public:BOOL InitInstance();第11页/共142页BOOL CMyAppInitInstance()/改写CWinApp的 /InitInstance函数CMyWin*pFrame=new CMyWin;pFrame-Create(0,_T(使用MFC的Win32 Application);/标题条pFrame-ShowWindow(1);/m_nCmdShow=1pFrame-Update
8、Window();this-m_pMainWnd=pFrame;return TRUE;CMyApp theApp;/全局对象第12页/共142页程序在编译前还要设置参数,使它能使用MFC类库。选择“Project”菜单的“Settings”项,弹出如图12.2所示的“Project Settings”对话框,在Microsoft Foundation Classes列表框中选择使用MFC。图12.3是编译运行的示意图,图12.4是类的组成图。这个程序比用Win32 API函数写的要简短一些,而且随着程序规模的增大,会很快显示出它的优点,编程量也会大大减小。第13页/共142页图12.2 设置
9、使用MFC示意图第14页/共142页图12.3 运行示意图第15页/共142页图12.4 类的组成图和全局变量第16页/共142页这个程序声明了两个类:由应用程序类CWinApp派生而来的CMyApp类和由框架窗口类CFrameWnd派生而来的CMyWin类。这两个类在MFC中的地位如图12.5所示。如果写过Win32 API程序,应该能分析出上面程序的来龙去脉。第17页/共142页图12.5 CWinApp类和CFrameWnd类在MFC中的地位示意图第18页/共142页Win32程序中有WinMain和WndProc函数。对于MFC程序来说,这两个函数在哪里?程序如何工作呢?1.全局对象W
10、inMain和WndProc函数被封装在类库里,从而免去用户手写的麻烦。上面用到的CWinApp代表程序体,CFrameWnd则代表一个主框架窗口。MFC的基类名均以字母C开头,习惯上为使用MFC编写的应用程序中的类起名时也是这样做。简单分析第19页/共142页【例12.1】演示了程序使用theApp全局对象。对比图12.1和图12.4的类结构图,它们都有一个全局对象theApp。main在图12.1中以全局函数身份出现,WinMain没有像main那样出现在图12.4中。简单说来,是MFC应用程序将它封装起来,只展现出theApp全局对象。2.WinMain函数寻迹Windows 操作系统在
11、初始化该应用程序进程的同时,将自动为该应用程序创建一个主线程,并将控制权交与C/C+运行时(Runtime)库的启动函数。注意程序中定义了一个全局对象:CMyApp theApp;第20页/共142页此时,其构造函数会被调用,初始化对象的数据成员,随后程序就进入主函数入口了。为了简少程序员的工作量。将原来的大量Windows API分门别类、有组织地进行封装,主函数和窗口函数也不例外。如【例12.2】所示,程序员现在只要从MFC类派生相应的类并产生一个全局对象即可。WinMain所在的位置可参见MFC源码的appmodule.cpp中的如下代码段:extern C int WINAPI_tWi
12、nMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,第21页/共142页 LPTSTR lpCmdLine,int nCmdShow)/call shared/exported WinMainreturn AfxWinMain(hInstance,hPrevInstance,lpCmdLine,nCmdShow);“_t”是为了支持Unicode而准备的一个宏。MFC已为用户准备好这个有相当程度固定行为的函数,它仅仅调用了AfxWinMain。AfxWinMain又做了什么?下面是简化的行为:第22页/共142页int AFXAPI AfxWin
13、Main(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)/AfxGetThread()返回指向当前线程的指针CWinThread*pThread=AfxGetThread();/AfxGetApp()获得全局对象theApp /pApp指向全局对象theAppCWinApp*pApp=AfxGetApp();AfxWinInit(hInstance,hPrevInstance,lpCmdLine,nCmdShow);第23页/共142页/CMyApp继承CwinApp虚函数InitApplic
14、ation/调用CWinApp InitApplication()pApp-InitApplication();/CMyApp改写CwinApp的 /虚函数 InitApplication /调用CMyApp InitApplication()pThread-InitInstance();pThread-Run();/进入消息循环 AfxWinTerm();return nReturnCode;第24页/共142页AfxGetApp是一个全局函数,返回应用程序对象的指针。这里是取得指向CMyApp类的全局对象theApp的指针。CMyApp继承CWinApp,CMyAppInitInstanc
15、e()被AfxWinMain间接调用到,于是就创建了应用程序窗口。在第11章解释过如下两个函数:MyRegisterClass(hInstance);/注册窗口 InitInstance(hInstance,nCmdShow)/初始化窗口 如将MyRegisterClass(hInstance)改名为 InitApplication(hInstance),则与InitInstance函数一起,正好成了现在MFC的CWinApp的两个虚函数。第25页/共142页InitApplication负责为每一个程序只注册一次窗口类,而InitInstance则为每一个例程都做一次初始化。所以,CWinA
16、pp的派生类CMyApp不需要改写InitApplication虚函数,但需要改写InitInstance虚函数,并在其中把窗口产生出来。调用由CWinApp类继承的Run()成员函数进入消息循环。程序结束时则调用CWinApp的ExitInstance()函数退出。既然WinMain的困惑没有了,WndProc也一样,读者若有兴趣可读一读MFC源码。第26页/共142页3.消息循环在注册了窗口类和创建了窗口之后,就要靠消息循环了。这就该CWinThreadRun()表演了。int CWinThreadRun().if(!PumpMessage()return ExitInstance();.
17、下面是CWinThreadPumpMessage()的代码:第27页/共142页BOOL CWinThreadPumpMessage()if(!GetMessage(&m_msgCur,NULL,NULL,NULL)return FALSE;if(m_msgCur.message!=WM_KICKIDLE&!PreTranslateMessage(&m_msgCur)TranslateMessage(&m_msgCur);DispatchMessage(&m_msgCur);return TRUE;第28页/共142页原来熟悉的消息循环在此。用C写Win32程序时,处理消息是在窗口子过程中的巨
18、大而复杂的switch/case中,而MFC采用消息映射机制来决定如何处理特定的消息。这种消息映射机制包括一组宏、映射成员函数等。剖析相关的宏不是本教材的任务,故这里仅介绍手工编写的方法。虽然以后是用向导而不必手工输入,但初学时还是知道一点原理为好。本程序需要在处理WM_PAINT消息时输出一字符串,就以此为例简单说明消息宏的使用。首先在窗口类(即要处理消息的类,这里是CMyWin)的定义中加入宏:第29页/共142页 DECLARE_MESSAGE_MAP();然后在实现文件中使用一对由 BEGIN_MESSAGE_MAP()开始,END_MESSAGE_MAP()结束的程序体。BEGIN_
19、MESSAGE_MAP()的两个参数分别为处理消息的类及其基类,此两宏建造了一个类似于11.3节所述的大表格;接着制造表中每项,这由ON_.宏完成,它们都是标准的,由MFC定义。例如要处理WM_PAINT消息,就应该用ON_WM_PAINT()宏,用户处理程序默认的是“类名OnPaint()”函数。下面是这个程序的源码:第30页/共142页class CMyWin:public CFrameWnd public:CMyWin()protected:afx_msg void OnPaint();/声明消息处理函数DECLARE_MESSAGE_MAP()/声明宏;/CFrameWnd是CMyWi
20、n的基类BEGIN_MESSAGE_MAP(CMyWin,CFrameWnd)ON_WM_PAINT()/对应CMyWinOnPaint()END_MESSAGE_MAP()第31页/共142页从程序中可以看出,具有消息的函数用afx_msg 标识。如图12.5所示,处理消息的基类是CCmdTarget,各个派生类继承这个消息处理机制。回忆11.3节用数组实现的消息处理,很容易发现MFC使用的是同一原理,只是设计了功能强大的宏帮助实现。4.程序结构总结从程序中可以看出,由于MFC已经把Windows API都封装起来了,程序代码已经没有原来熟悉的结构了。简单说来,看不到WinMain,不知道程
21、序从何处开始执行;看不到如何注册窗口类;看不到消息循环和窗口处理函数。第32页/共142页其实,它现在变得很简单。下面假设程序运行处理WM_PAINT消息,可分为准备、运行和结束阶段,分析各个阶段的过程。(1)程序的准备阶段程序的准备工作可分为如下几个过程:theApp是应用程序的全局对象,代表整个程序,其基类是CWinApp,产生theApp,配置内存并建 立初值;函数AfxWinMain通过AfxWinIni函数调用 AfxInitThread函数设置消息队列;AfxWinMain调用Application函数,它是 CWinApp的虚函数,AfxWinMain一般只是调 用而不改写它;第
22、33页/共142页 AfxWinMain调用InitInstance函数,它是 CWinApp的空虚函数,必须重新定义它;定义CWinApp派生类CMyApp的空虚函数 CMyApp InitInstance()。框架对象代表主窗口,其基类是CFrameWnd,CMyWin*pFrame=new CMyWin;语句使用“new”创建一个CMyWin 的对象,程序中 将CMyWin的构造函数设计为空函数;使用函数Create产生主窗口,然后写入标题条内容;执行函数ShowWindow显示窗口;执行函数UpdateWindow,发出WM_PAINT消息;执行函数Run,进入消息循环。第34页/共1
23、42页(2)程序的运行阶段程序运行的过程如下:程序由CwinAppRun()中的GetMessage()循环获得WM_PAINT消息;WM_PAINT经由DispatchMessage()送到窗口 函数CWndDefWindowProc()中;CWndDefWindowProc()将消息传递并通过 消息映射表格(Message Map);在传递过程中发现有相符合的项目,就调用项 目中对应的函数,此函数是应用程序利用 BEGIN_MESSAGE_MAP和 END_MESSAGE_MAP之间的宏设立起来的;第35页/共142页系统提供处理标准消息的标准命名方法,例如 WM_PAINT由函数OnPa
24、int处理,这里的程序也 将消息处理函数声明为afx_msg void OnPaint()。(3)程序的结束阶段程序结束的过程为:本程序的CMyWin没有处理WM_CLOSE消息,如果使用“文件”菜单的“关闭”命令,则交给默认 的处理程序,默认函数调用DestroyWindow()并发出WM_DESTROY消息;默认的WM_DESTROY处理方式是调用 PostQuitMessage(),发出WM_QUIT;CWinAppRun()接收WM_OUIT,结束消息 循环;第36页/共142页然后调用CWinApp的虚函数ExitInstrance,但 最终是执行CWinAppExitInstran
25、ce(),还是CMyAppExitInstrance(),则决定于CMyApp是否改写了ExitInstrance 函数;最后执行函数AfxWinTerm结束程序。由此可见,我们主要是产生两个派生类。CWinApp类提供的4个关键虚成员函数如下:virtual BOOL InitAppLication();/构建窗口 virtual BOOL InitInstance()/与窗口有关的空函数 virtual in Run();/处理消息 virtual intExitInstance();/结束运行注意:派生类一定要改写虚函数InitInstance。第37页/共142页AppWizard生成
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C及Windows可视化程序设计 刘振安著 Windows 可视化 程序设计
限制150内