VC++讲义第09单元WINDOWS编程.docx
- 文档编号:10168009
- 上传时间:2023-02-09
- 格式:DOCX
- 页数:30
- 大小:58.87KB
VC++讲义第09单元WINDOWS编程.docx
《VC++讲义第09单元WINDOWS编程.docx》由会员分享,可在线阅读,更多相关《VC++讲义第09单元WINDOWS编程.docx(30页珍藏版)》请在冰豆网上搜索。
VC++讲义第09单元WINDOWS编程
第9单元WINDOWS编程
教学目标
介绍WINDOWS编程的基本思想和MFC程序的基本结构。
学习要求
理解WINDOWS的基本编程思想,特别是其消息传递机制,弄清MFC程序的组成及各部分的作用。
授课内容
MicrosoftWindows是广泛应用的台式机计算机操作系统,具有图形用户界面和多任务、多窗口等特点。
目前Windows已成为微机上的主流操作系统,几乎一统天下,在Windows平台上进行软件开发也已成为程序设计的主流。
9.1WINDOWS编程的基本思想
应用程序
Windows
取消息
消息队列
键盘消息
处理消息
鼠标消息
其他消息
图9-1事件驱动原理
Windows编程使用事件驱动的程序设计思想。
在事件驱动的程序结构中,程序的控制流程不再由事件的预定发生顺序来决定,而是由实际运行时各种事件的实际发生来触发,而事件的发生可能是随机的、不确定的,并没有预定的顺序。
事件驱动的程序允许用户用各种合理的顺序来安排程序的流程。
对于需要用户交互的应用程序来说,事件驱动的程序设计有着传统程序设计方法无法替代的优点。
事件驱动是一种面向用户的程序设计方法,在程序设计过程中除了完成所需要的程序功能之外,更多的考虑了用户可能的各种输入(消息),并有针对性地设计相应的处理程序。
事件驱动程序设计也是一种“被动”式的程序设计方法,程序开始运行时,处于等待消息状态,然后取得消息并对其作出相应反应,处理完毕后又返回处于等待消息的状态。
使用事件驱动原理的程序的工作流程如图9-1所示。
事件驱动围绕着消息的产生与处理展开,事件驱动是靠消息循环机制来实现的。
消息是一种报告有关事件发生的通知。
Windows应用程序的消息来源有以下四种:
(1)输入消息:
包括键盘和鼠标的输入。
这一类消息首先放在系统消息队列中,然后由Windows将它们送入应用程序消息队列中,由应用程序来处理消息。
(2)控制消息:
用来与Windows的控制对象,如列表框、按钮、检查框等进行双向通信。
当用户在列表框中改动当前选择或改变了检查框的状态时发出此类消息。
这类消息一般不经过应用程序消息队列,而是直接发送到控制对象上去。
(3)系统消息:
对程序化的事件或系统时钟中断作出反应。
一些系统消息,象DDE消息(动态数据交换消息)要通过Windows的系统消息队列,而有的则不通过系统消息队列而直接送入应用程序的消息队列,如创建窗口消息。
(4)用户消息:
这是程序员自己定义并在应用程序中主动发出的,一般由应用程序的某一部分内部处理。
9.2MFC编程
Microsoft提供了一个基础类库MFC(MicrosoftFoundationClass),其中包含用来开发C++应用程序和Windows应用程序的一组类。
这些类用来表示窗口、对话框、设备上下文、公共GDI对象如画笔、调色板、控制框和其他标准的Windows部件,封装了大部分的WindowsAPI(ApplicationProgrammingInterface:
应用程序接口)。
使用MFC,可以大大简化Windows编程工作。
MFC中的类可分为两种:
CObject类的派生类及非CObject派生类。
非CObject派生类数量不多,但大都很常用。
几个常用的非CObject派生类如CTime,CTimeSpan,CString和CFile已分别在第7单元和第8单元中介绍过。
CObject派生类的基本特征为:
支持序列化(Serialize,应用见第13单元)、运行时类信息访问(Dynamic,应用见第12单元)、对象诊断输出(参看10.6.4:
“CObject:
:
Dump()成员函数”)和与集合类兼容(参看12.7:
“集合类”)等。
MFC将Windows应用程序从开始运行、消息传递到结束运行所需的各步骤均封装在CWinApp类中,CWinApp类表示MFC应用程序的应用对象。
CWinApp类从CObject类的子类CWinThread类(定义MFC内的线程行为)派生。
一个MFC应用程序必须有且只能有一个从WinApp类派生的全局应用程序对象,此对象在运行时刻控制应用程序中所有其他对象的活动。
典型的Windows应用程序结构有以下四种:
(1)控制台应用程序:
在本教程第1单元到第8单元介绍的所有程序均为控制台应用程序。
控制台应用程序结构简单,可以不使用MFC类库。
(2)基于框架窗口的应用程序:
某些应用程序仅需最小的用户界面和简单的窗口结构,这时可使用基于框架窗口的方案。
在此方案中,主应用程序窗口为框架窗口,CFrameWnd派生类对象附属于应用程序的CWinApp派生类对象的m_pMainWnd成员。
第9单元到第11单元的例题程序均为基于框架窗口的程序。
(3)基于对话框的应用程序:
基于对话框的应用程序与基于框架窗口的应用程序差别不大,只是用CDialog派生类对象代替了CFrameWnd派生类对象作为应用程序的主窗口。
基于对话框的应用程序框架可由VisualC++的应用向导自动生成,非常方便。
第15单元介绍了基于对话框的应用程序。
(4)基于文档/视图结构的应用程序:
文档/视图应用具有较复杂的结构,当然其功能也相应增强。
基于文档/视图结构的应用程序又可分为单文档界面(SDI,在第12单元介绍)和多文档界面(MDI,在第16单元介绍),后者更复杂些。
MFC类的结构大都比较复杂,可能包含数十个至数百个成员函数,加上层次相当多的继承关系,很难把握。
MFC程序的结构也因此变得难以详细分析。
学习MFC,最重要的一点是要学会抽象地把握问题,不求甚解。
不要一开始学习VisualC++就试图了解整个MFC类库,实际上那几乎是不可能的。
一般的学习方法是,先大体上对MFC有个了解,知道它的概念、组成等之后,从较简单的类入手,由浅入深,循序渐进、日积月累的学习。
一开始使用MFC提供的类时,只需要知道它的一些常用的方法、外部接口,不必要去了解它的细节和内部实现,把它当做一个模块或者说黑盒子来用,这就是一种抽象的学习方法。
在学到一定程度时,再深入研究,采用继承的方法对原有的类的行为进行修改和扩充,派生出自己所需的类。
在研究MFC的类时,要充分利用MSDN内的帮助信息。
学习MFC,很重要的一点是理解MFC应用程序的框架结构,而不是强迫记忆大量的类成员、方法及其参数等细节。
[例9-1]吹泡泡程序。
每当用户在窗口客户区中按下鼠标左键时即可产生一个泡泡(灰色圆形)。
设计思想:
显示一个泡泡所需的数据包括其位置和大小,在MFC中可用其包含矩形表示。
可设置一数组,每当用户按下鼠标左键时,就产生一个泡泡的数据存入数组中,再由框架窗口类的OnDraw()函数显示所有的泡泡。
说明:
参考9.8:
“用VisualC++集成开发环境开发Win32应用程序”建立该项目。
程序:
//Example9-1:
吹泡泡程序
#include
//框架窗口类
#defineMAX_BUBBLE250
classCMyWnd:
publicCFrameWnd
{
CRectm_rectBubble[MAX_BUBBLE];
intm_nBubbleCount;
public:
CMyWnd(){m_nBubbleCount=0;}
protected:
afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);
afx_msgvoidOnPaint();
DECLARE_MESSAGE_MAP()
};
//消息映射
BEGIN_MESSAGE_MAP(CMyWnd,CFrameWnd)
ON_WM_LBUTTONDOWN()
ON_WM_PAINT()
END_MESSAGE_MAP()
//框架窗口类的成员函数
voidCMyWnd:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
if(m_nBubbleCount { intr=rand()%50+10; CRectrect(point.x-r,point.y-r,point.x+r,point.y+r); m_rectBubble[m_nBubbleCount]=rect; m_nBubbleCount++; InvalidateRect(rect,FALSE); } } voidCMyWnd: : OnPaint() { CPaintDCdc(this); dc.SelectStockObject(LTGRAY_BRUSH); for(inti=0;i dc.Ellipse(m_rectBubble[i]); } //应用程序类 classCMyApp: publicCWinApp { public: BOOLInitInstance(); }; //应用程序类的成员函数 BOOLCMyApp: : InitInstance() { CMyWnd*pFrame=newCMyWnd; pFrame->Create(0,_T("吹泡泡")); pFrame->ShowWindow(m_nCmdShow); this->m_pMainWnd=pFrame; returnTRUE; } //全局应用程序对象 CMyAppThisApp; 图9-2吹泡泡程序 输出: 每在窗口客户区按一下鼠标左键,可绘出一个灰色泡泡,其大小是随机确定的。 吹泡泡程序的运行情况见图9-2。 分析: 尽管这是一个非常简单的MFC程序,却也有几十行代码。 这是因为Window应用程序要管理远比字符界面(如本教程前面所用的控制台界面)复杂的图形用户接口,而且要有多任务并行处理的能力。 但是,随着程序规模的增大,用MFC编程的优点很快会显露: 由于结构清晰,各部分功能明确,代码规范,编程和调试的工作量大为减少。 该程序声明了两个类,一个是由应用程序类CWinApp中派生出来的CMyApp类,一个是从框架窗口CFrameWnd类派生出来的CMyWnd类。 MFC的基本类名均以字母C打头,习惯上在为使用MFC编写的应用程序中的类起名时也这么做。 除此而外,在程序中还声明了一个CMyApp类的全局对象ThisApp。 仔细阅读程序还会发现,该程序似乎不完整,其中既没有主函数(在一般的Windows程序中应为WinMain()函数),也没有实现消息循环的程序段。 然而,这是一种误解,因为MFC已经把它们封装起来了。 在程序运行时,MFC应用程序首先调用由框架提供的标准的WinMain()函数。 在WinMain()函数中,先初始化由CMyApp定义的唯一全局对象ThisApp(通过重载的虚函数InitInstance(),它构造并显示应用程序的主窗口),然后调用其由CWinApp类继承的Run()成员函数,进入消息循环。 程序结束时时调用CWinApp的ExitInstance()函数退出。 因此,应用程序框架不仅提供了构建应用程序所需要的类(CWinApp,CFrameWnd等),还规定了程序的基本执行结构。 所有的应用程序都在这个基本结构的基础上完成不同的功能。 MFC采用消息映射机制来决定如何处理特定的消息。 这种消息映射机制包括一组宏,用于标识消息处理函数、映射类成员函数和对应的消息等。 在类CMyWnd的声明中,前面有afx_msg标记的成员函数就是消息处理成员函数。 如果在程序中用到了消息处理函数,那么还需对程序执行部分所定义的消息映射进行初始化,这项工作是通过消息映射宏完成的。 消息映射宏就是程序中从BEGIN_MESSAGE_MAP()到END_MESSAGE_MAP()的程序段。 BEGIN_MESSAGE_MAP()宏包含两个参数CMyWnd和CFrameWnd,分别是当前定义的窗口类及其父类的名称。 在BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()之间,含有该窗口类要处理的各种Windows消息的入口。 MFC包含了大量的预定义消息映射宏,用来指定各种成员函数与各种形如WM_××××的消息相对应,如ON_WM_LBUTTONDOWN宏指定WM_LBUTTONDOWN消息的处理成员函数为OnLButtonDown()。 这时,只需要写出要处理的消息就够了,不必再写出处理函数名。 我们在CMyWnd类中声明了一个数组成员m_rectBubble,用于存放泡泡的数据(这里是圆的包含矩形)。 另外还声明了一个整型数据成员m_nBubbleCount,用来存放数组中泡泡的实际数量。 在框架窗口类的构造函数中该成员变量被初始化为0。 由于构造函数非常简单,所以使用了内联函数形式。 OnPaint()函数根据数组m_rectBubble的内容画出一个个泡泡。 OnPaint()函数在窗口生成、大小改变或覆盖在其上的其他窗口被移开时被自动调用。 其中语句 dc.SelectStockObject(LTGRAY_BRUSH); 用于选择一个库存画刷,画刷决定了所画图形(如椭圆、矩形和多边形等)内部的颜色。 (参看10.5: “库存图形对象”)。 在处理鼠标消息的OnLButtonDown()函数中,语句 intr=rand()%50+10; 随机确定了要画出的泡泡半径(范围为10~50),其中全局函数rand()可产生一个随机整数。 而语句 CRectrect(point.x-r,point.y-r,point.x+r,point.y+r); m_rectBubble[m_nBubbleCount]=rect; m_nBubbleCount++; 使用鼠标位置point和半径r构造一个泡泡的包含矩形并将其存入数组m_rectBubble。 语句 InvalidateRect(rect,FALSE); 用于通知OnPaint()函数更新窗口客户区指定区域的内容。 我们记得,OnPaint()函数只在窗口生成、大小改变或覆盖其上的其他对象移动时调用,因此在数据发生变动(如增加泡泡)时则需用CWnd类的成员函数InvalidateRect()函数通知OnPaint()函数重画窗口客户区中的部分区域。 9.3在窗口的客户区输出文字和图形 例9-1中的OnPaint()函数用于绘制客户区的内容。 要完成这项任务,需要先建立一个设备环境(DeviceContext),这可以通过声明一个CPaintDC类的对象dc实现。 在声明语句中,应将当前窗口对象指针this传给CPaintDC类的构造函数,把绘制区域确定为当前窗口的客户区。 Windows在窗口更新、移动、改变尺寸或移去覆盖在其上的其他窗口对象时均会向该窗口发送WM_PAINT消息,从而触发应用程序调用OnPaint()函数重绘窗口客户区。 CPaintDC类中封装了大量的绘图和文字输出方法(成员函数),如: 1.文字信息显示 BOOLTextOut(intx,inty,LPCTSTRlpszString); 在指定坐标(x,y)处显示字符串lpszString的内容,显示成功返回非0值,否则返回0。 坐标原点(0,0)在客户区左上角,Y轴向下。 下面各成员函数的坐标参数均同此。 参数类型LPCTSTR和返回值类型BOOL均为Windows的数据类型,前者意为常量字符指针,后者为逻辑类型。 下面的COLORREF,POINT,LPPOINT,LPCRECT等均类此。 关于这些Windows类型,请参看9.7: “Windows数据类型与变量的命名规则”。 2.画点 COLORREFSetPixel(intx,inty,COLORREFcolor); COLORREFSetPixel(POINTpoint,COLORREFcolor); 该函数在指定坐标(用参数x,y或点point给出)处按给定颜色(color)画点,返回值为原来此坐标处的颜色。 3.取指定坐标点的颜色 COLORREFGetPixel(intx,inty)const; COLORREFGetPixel(POINTpoint)const; 返回值为指定坐标处的颜色。 4.画线 画线工作需经两步完成: 首先确定线的起始端位置,这可通过调用成员函数MoveTo完成,其原型为: CPointMoveTo(intx,inty); CPointMoveTo(POINTpoint); MoveTo将绘图位置(“看不见”)移至指定坐标处,并返回移动前的绘图位置。 确定了线的起点后,即可使用成员函数LineTo画线: BOOLLineTo(intx,inty); BOOLLineTo(POINTpoint); 其参数为线终点的坐标。 5.绘制矩形 绘制矩形的成员函数为: BOOLRectangle(intx1,inty1,intx2,inty2); BOOLRectangle(LPCRECTlpRect); 其参数为需要绘制的矩形的左上角坐标(x1,y1)和右下角坐标(x2,y2)。 (x1,y1) (x2,y2) 图9-3椭圆的包含矩形 6.绘制椭圆 该成员函数的原型为: BOOLEllipse(intx1,inty1,intx2,inty2); BOOLEllipse(LPCRECTlpRect); 其参数的含义为所绘椭圆的包含矩形的左上角和右下角坐标,如图9-3所示。 7.画多边形 BOOLPolygon(LPPOINTlpPoints,intnCount); 其中参数lpPoints为一LPPOINT类型的指针,可用CPoint数组(存放多边形的各顶点坐标)作为实参。 参数nCount为顶点个数。 例如 CPaintDCdc(this); CPointpointPoly[3]; pointPoly[0]=CPoint(100,100); pointPoly[1]=CPoint(200,100); pointPoly[2]=CPoint(200,200); dc.Polygon(pointPoly,3); 在窗口客户区相应位置画出一个三角形。 8.其他绘图函数还有画弧Arc()、画弓形Chord()、画扇型Pie()和画圆角矩形InvertRect()等,具体使用方法可参看MSDN联机帮助。 9.获取客户区的坐标 为了某些绘图效果,可能需要知道框架窗口客户区当前的大小。 Wnd类的成员函数GetClientRect()可用于该目的。 其调用方法为: voidGetClientRect(LPRECTlpRect); [例9-2]修改例9-1中的OnDraw()函数,使之可在客户区中央显示一矩形框,并在其中显示文字信息“Hello,MFC! ”。 说明: 建立项目的方法见9.8: “用VisualC++集成开发环境开发Win32应用程序”。 程序: 用下面的程序段替代例9-1中的OnPaint()函数。 //Example9-2: 在窗口客户区显示矩形框和文字 voidCMyWnd: : OnPaint() { CPaintDCdc(this); dc.SelectStockObject(LTGRAY_BRUSH); for(inti=0;i dc.Ellipse(m_rectBubble[i]); CRectrectClient,rectTitle; intnWidth=100; intnHeight=40; GetClientRect(&rectClient); rectTitle.left=(rectClient.Width()-nWidth)/2; rectTitle.top=(rectClient.Height()-nHeight)/2; rectTitle.right=rectTitle.left+nWidth; rectTitle.bottom=rectTitle.top+nHeight; dc.SelectStockObject(WHITE_BRUSH); dc.Rectangle(rectTitle); dc.TextOut(rectTitle.left+10,rectTitle.top+10,"Hello,MFC! "); } 输入输出: 与例9-1类似,只是在窗口中央显示了一个矩形框,框中显示相应文字,见图9-4。 图9-4新吹泡泡程序 分析: 该程序系在例9-1的程序基础上改编。 可以看出,这两个程序不但结构相同,而且大部分代码也完全一样。 这是MFC编程的一个显著特点,即可通过修改一个通用程序框架来快速构造自己的程序。 自学内容 9.4WINDOWS的用户界面对象 Windows支持丰富的用户界面对象,包括窗口、图标、菜单、对话框等等。 程序员只需简单的几十行代码,就可以设计出一个非常漂亮的图形用户界面。 下面我们介绍几个常用的用户界面对象的术语和相关概念。 9.4.1窗口 图9-5典型窗口 窗口是用户界面中最重要的部分,是屏幕上与一个应用程序相对应的矩形区域,是用户与产生该窗口的应用程序之间的可视界面。 每当用户开始运行一个应用程序时,应用程序就创建并显示一个窗口;当用户操作窗口中的对象时,程序会作出相应反应。 用户通过关闭一个窗口来终止一个程序的运行;通过选择相应的应用程序窗口来选择相应的应用程序。 一个典型的窗口外观如图9-5所示。 绝大多数窗口都有一个边框,用于指示窗口的边界,同时也用来指明该窗口是否为活动窗口,当窗口活动时,边框的标题栏部分呈高亮显示。 用户可以用鼠标拖动边框来调整窗口的大小。 在程序设计时,称窗口活动为获得焦点,非活动窗口为失去焦点。 9.4.2系统菜单 系统菜单图标位于窗口左上角,用鼠标点一下该图标(或按ALT+空格键)就可弹出系统菜单。 系统菜单提供标准的应用程序选项,包括Restore(还原窗口原有的大小),Move(使窗口可以通过键盘上的光标键来移动其位置),Size(使用光标键调整窗口大小),Minimize(将窗口缩成图标),Maximize(最大化: 使窗口充满整个屏幕)和Close(关闭窗口)。 9.4.3标题栏 标题栏位于窗口的顶部,其中显示的文本信息用于标注应用程序,一般是应用程序的名字,以便让用户了解哪个应用程序正在运行。 标题栏颜色反映该窗口是否是一个活动窗口(活动窗口的标题栏呈醒目颜色)。 鼠标双击标题栏可使窗口在正常大小和最大化状态之间切换。 在标题栏上按下鼠标器左键可以拖动并移动该窗口,按右键弹出系统菜单。 9.4.4菜单栏 菜单栏位于标题栏下方,横跨窗口,上面列出了应用程序所支持的命令。 菜单栏中的项目一般是一类命令或操作的通称,如文件操作、编辑操作和帮助等。 从菜单栏中选中某一项通常会显示一个弹出菜单,其中的项是对应于指定命令或类中的某个任务。 通过选择菜单中的一个项(菜单项),用户可以向程序发出命令,以执行某一功能。 如选择“文件操作”菜单
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VC+讲义第09单元 WINDOWS编程 VC 讲义 09 单元 WINDOWS 编程