还剩27页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
VisualC++图形程序设计基础
一、前言VisualC++是在MicrosoftC的基础上发展而来的,随着计算机软、硬件技术的快速发展,如今VisualC++已成为集编辑、编译、运行、调试于一体功能强大的集成编程环境本章以VisualC++
6.0为对象,主要介绍VisualC++集成编成环境的使用、图形设备接口和常用图形程序设计、鼠标编程以及菜单设计等基础,目的是通过对VisualC++的学习,掌握VisualC++图形程序设计的方法,为计算机图形学原理部分的算法实现提供程序工具和方法大致以下目的1.学习VisualC++图形程序设计的方法;2.掌握VisualC++集成编成环境的使用、图形设备接口和常用图形程序设计、鼠标编程、橡皮筋交互技术、画刷与画笔以及菜单设计等;
二、VisualC++图形程序设计基础2.1VisualC++
6.0应用程序开发方法介绍VisualC++
6.0集成开发环境,以一个简单的实例介绍利用VisualC++应用程序工程建立方法和程序设计框架2.1.1VisualC++的集成开发环境从开始菜单中启动VisualC++
6.0,进入开发集成环境打开一个项目后,可以看到VisualC++
6.0的开发环境由标题栏、工具栏、工作区窗口、源代码编辑窗口、输出窗口和状态栏组成,见图2.1所示标题栏用于显示应用程序名和所打开的文件名,标题栏的颜色可以表明对应窗口是否被激活菜单栏包括文件、编辑、显示、插入、工程、编译、工具、窗口和帮助九项主菜单,包含了从源代码的编辑、界面设计、程序调试和编译运行在内的所有功能工具栏列出了常用的菜单命令功能和对象方法工具栏的下面是两个窗口,一个是工作区窗口,用于列出工程中的各种对象,一个是源代码编辑窗口,用于各个对象的程序设计输出窗口显示项目建立过程中所产生的各种信息屏幕底端是状态栏,它给出当前操作或所选择命令的提示信息标题栏菜单栏工作区源代码编辑窗口状态栏图2.1VisualC++
6.0集成开发环境2.1.2应用程序工程的建立方法VisualC++提供了一种称为AppWizard的工具,利用该工具,用户可以方便地按照自己的需要创建符合需要的应用程序框架在这个基础上,用户可以进一步将自己编写的程序加入到这个框架中,实现用户程序的功能下面介绍建立VcApp应用程序框架的方法,其它应用程序的方法都与此类似第一步启动VisualC++选择工程方法从开始菜单中选择VisualC++,进入VisualC++集成环境从文件菜单中选择新建New命令,弹出图3-2对话框切换到工程(Projects)标签,项目类型选择MFCAppWizardexe,输入工程的名字(如VcApp),选择项目放置的位置,然后单击“确定”按钮图3-2VisualC++的New对话框第二步设置应用程序的特性这些设置包括六个问题,每一个问题都有不同的选项供选择一个问题选择完后,通过“下一步”(Next)选择下一个问题,直到六个问题选择完毕还可以通过“上一步”Back返回上一个问题重新选择下面继续上面的例子,在单击“确定”按钮后,弹出第一个问题窗口,如图3-3所示第一个问题是建立什么类型的应用程序,有三个选项单个文档(Singledocument)、多重文档(Multipledocument)和基本对话(Dialogbased)单个文档应用程序主窗口中只有一个窗口,多重文档可以在主窗口中开多个子窗口,基本对话主窗口是一个对话框例中选择单个文档,单击“确定”,进入下一个问题,如图3-4所示第二个问题是数据库的支持,是否用ODBC存取数据库,有四个选项不包括数据库的支持(None)、仅包含ODBC头文件(Headerfilesonly)、指定一个数据库但没有文件支持和指定一个数据库但需要文件支持当选择了后两项,则需要用户选择一个已经建立的数据库例中不需要数据库支持,选择第一个选项“否”,进入第三个问题,如图3-5所示图3-3第一个问题选择应用程序的类型图3-4第二个问题选择是否要用ODBC支持第三个问题是对ActiveX的支持有五个选项
(1)没有对ActiveX的支持;
(2)ActiveX容器,它可以包含链接和嵌入对象容器不能为其它的ActiveX程序提供支持,它只能维护嵌入对象;
(3)微型服务器(Mini-server),应用程序不能独立运行,只能被调用为其它程序建立ActiveX对象
(4)完整服务器(Full-server),它能够独立运行,并能够为其它应用程序建立ActiveX对象
(5)容器和服务器,一个应用程序可以同时是容器和服务器在例子中,选择第一个选项,没有对ActiveX的支持,单击“下一个”(Next)进入下一个问题图3-5第三个问题选择是否对ActiveX的支持第四个问题是应用程序的特性和高级选项,如图3-6所示图3-6应用程序的特性和高级选项例中全部采用默认选项,进入下一个问题第五个问题是项目的风格、原文件注释和MFC库类型,如图3-7所示在例子中全部采用默认选项,进入第六个问题第六个问题是确定类名和文件名,如图3-8所示基于第一个问题到第五个问题的回答,AppWizard会把将要建立的新类的名称通知用户AppWizard将为应用程序建立四个新类,CVcAppApp是应用程序类,它是CWinApp的派生类CMainFrame是一个拥有应用程序主窗口的类CVcAppDoc和CVcAppView是该应用程序的文档和视图类这些名字用户可以改变最后单击“完成”(Finish)显示所建项目的信息,单击“确定”后,项目建立完成图3-7项目的风格、原文件注释和MFC库类型图3-8通知MFC产生的类名称2.1.3输入源程序进行程序设计应用程序项目工程建立以后,就为应用程序的开发建立了一个框架,这是不输入任何程序代码,对该项目程序进行编译和运行,可以生成一个完整的窗口程序用户根据项目工程中的不同类,输入自己设计的程序代码,完成用户的程序设计例如,从VcAppClasses中找到CVcAppView的OnDraw()函数,如图3-9所示双击OnDraw()函数,这时系统会打开VcAppView.cpp文件,而且光标正置于OnDraw()函数中,在其中输入下列语句pDc-TextOut3030”同学们好,欢迎使用VC++编程!”;编译并运行该程序,运行结果如图3-10所示图3-9输入程序源代码图3-10运行结果2.2图形设备接口和图形程序设计2.2.1图形设备接口简介在Windows系统中,程序都是通过一个叫做图形设备接口(GDIGraphicsDeviceInterface)的抽象接口和硬件打交道,Windows会自动将设备环境表映射到相应的物理设备,并且会提供正确的输入/输出指令GDI是Windows系统核心的三种动态链接库之一,它管理Windows系统的所有程序的图形输出在Windows系统中,GDI向程序员提供了高层次的绘图函数,只要掌握这些绘图函数,就可以很方便地进行图形程序设计另一个概念是设备描述表(DCDeviceContext)DC是一个数据结构,当程序向GDI设备中绘图时,需要访问该设备的DCMFC将GDI的DC封装在C++类中,包括CDC类和CDC派生类,这些类中的许多成员都是对本地GDI绘图函数进行简单封装而形成的内联函数DC的作用就是提供程序与物理设备或者虚拟设备之间的联系,除此之外,DC还要处理绘图属性的设置,如文本的颜色等程序员可以通过调用专门的GDI函数修改绘图属性,如SetTextColor函数CDC类是GDI封装在MFC中最大的一个类,它表示总的DC表2.1列出了CDC中的一些常用绘图函数表2.1CDC类中常用绘图函数这些函数的语法和使用可以通过MSDN帮助查询2.
2.2节主要介绍Windows中基本图形,包括电、直线、圆、圆弧、矩形、椭圆、扇形、折线等程序设计2.2.2绘制基本图形
(1)画点SetPixel函数可以在指定的坐标位置按指定的颜色画点函数原型说明如下COLORREFCDC::SetPixelintXintYCOLORREFcrColor;其中,(X,Y)为点的坐标位置,crColor参数为点的颜色值如果函数调用成功,则函数返回像素的颜色值,否则返回值为-1颜色值通过RGBRedGreenBlue来设置,其中三个参数取值0~255例如,在VcAPP项目中,在CVcAppView类中的OnDraw函数中加入下列画点语句//绘制一组彩色点//绘制一组彩色点pDC-TextOut2020point:;pDC-SetPixel10020RGB25500;pDC-SetPixel11020RGB02550;pDC-SetPixel12020RGB00255;pDC-SetPixel10020RGB2552550;pDC-SetPixel10020RGB2550255;pDC-SetPixel10020RGB0255255;pDC-SetPixel10020RGB000;pDC-SetPixel10020RGB255255255;运行程序,查看运行结果
(2)画直线和折线画直线需要LineTo和MoveTo两个函数的配合使用LineTo函数以当前位置所在的点为直线的起点,另指定一个点为直线的终点,画出一段直线直线的颜色通过画笔的颜色来设定,在后面介绍LineTo函数原型说明如下BOOLCDC::LineTointnXEndintnYEnd;直线的终点位置由(nXEndnYEnd)指定如果函数调用成功,那么该点就成为当前位置,并返回TRUE,否则返回FALSEMoveTo函数只是将当前位置移动到指定位置,它并没有画出直线,其函数说明为BOOLCDC::MoveTointXintY;示例在CVcAppView类中的OnDraw函数中加入下列画点语句//绘制直线pDC-TextOut2060Line:;pDC-MoveTo2090;pDC-LineTo16090;Polyline函数用来画一条折线,而PolyPolyline函数则用来画多条折线,它们的函数原型说明如下BOOLCDC::PolylineCOUSTPOINT*lpptintcPoints;BOOLCDC::PolyPolylineCOUSTPOINT*lpptCOUSTDWORD*lpdwPolyPointsDWORDcCount;在Polyline函数中,lppt是指向折线顶点数组的指针,而cPoints是折线顶点数组中的顶点数例如,绘制一条具有4个顶点的折线,程序如下POINTpolylinepoint
[4]={{70240}{20190}{70190}{20240}};pDC-Polylinepolylinepoint4;在PolyPolyline()函数中,lppt是指向保存顶点数组的指针,而各条折线的顶点数则保存在lpdwPolyPoints参数所指向的数组中,最后的cCount参数指定折线的数目例如POINTpolypolylinePt
[9]={{95160}{120185}{120250}{145160}{120185}{90185}{150185}{80210}{160210}};DWORDdwPolyPoints
[4]={3222};//分四段折线,分别占用3,2,2,2个顶点pDC-PolyPolylinepolypolylinePtdwPolyPoints4;注由于一条折线至少需要2个顶点,因此dwPolyPoints数组中的数不应该小于2
(3)画弧线和曲线通过Arc函数画弧线或整个椭圆椭圆限定在一个矩形内,称为外接矩形Arc函数的圆形说明如下BOOLCDC::ArcintnLeftRectintnTopRectintnRightRectintnBottomRectintnXStartArcintnYStartArcintnXEndArcintnYEndArc;其中,(nLeftRectnTopRect)是外接矩形的左上角坐标值,(nRightRectnBottomRect)是外接矩形的右下角坐标值而椭圆中心与点(nXStartArcnYStartArc)所构成的射线与椭圆的交点成为弧线的起点,椭圆中心与点(nXEndArcnYEndArc)所构成的射线与椭圆的交点成为弧线的终点椭圆上从始点到终点就形成一条弧线在Windows系统中,弧线从始点到终点的方向是逆时针方向,但可以通过SetArcDirection函数将绘制弧线方向设置为顺时针方向示例,用Arc绘制圆、圆弧和椭圆,程序如下fori=0;i6;i++{pDC-Arc260-5*i70-5*i260+5*I70+5*i260+5*i70260+5*i70;}fori=3;i6;i++{pDC-Arc260-10*i70-10*i260+10*i70+10*iint260+10*i*cos60*2.1415926/180int70+10*i*sin60*2.1415926/180int260+10*i*cos60*2.1415926/180int70-10*i*sin60*2.1415926/180;pDC-Arc260-10*i70-10*i260+10*i70+10*iint260-10*i*cos60*2.1415926/180int70-10*i*sin60*2.1415926/180int260-10*i*cos60*2.1415926/180int70+10*i*sin60*2.1415926/180;}Bezier曲线是最常见的非规则曲线之一Bezier曲线属于三次曲线,需要四个控制顶点来确定一条Bezier曲线,其中曲线通过第一点和最后一点,并且第一条边和最后一条边是曲线在起点和终点处的切线,从而确定了曲线的走向PolyBezier函数可以画出一条或多条Bezier曲线,其函数原型说明如下BOOLCDC::PolyBezierCONSTPOINT*lpptDWORDcPoints;其中,lppt参数是曲线控制顶点所组成的数组,cPoints参数表示lppt数组中的顶点数,一条Bezier曲线需要四个控制顶点如果lppt数组用于画多条Bezier曲线,第二条以后的曲线只需要三个控制顶点,因为后面的曲线总是把前一条曲线的终点作为自己的起点示例,给出四个控制顶点,画出一条Bezier曲线和特征多边形//绘制Bezier曲线POINTpolyBezier
[4]={{20310}{60240}{120300}{160330}};pDC-PolylinepolyBezier4;pDC-PolyBezierpolyBezier4;
(4)画封闭曲线Windows中提供了一组画封闭曲线的函数,包括绘制矩形、多边性、椭圆等,这些画封闭曲线的函数不但可以利用画笔来画出轮廓线,同时还可以利用画刷来填充这些封闭曲线所围成的区域Rectangle函数用来画矩形,其函数原型说明如下BOOLCDC::RectangleintnLeftRectintnTopRectintnRightRectintnBottomRect;其中,参数nLeftRect和nTopRect给出了矩形左上角的坐标,而nRightRect和nBottomRect则给出矩形的右下角坐标Ellipse函数的作用则是画椭圆形在Ellipse函数中,椭圆是由其外接矩形来确定的,外接矩形的中心与椭圆中心重合,矩形的长与宽和椭圆的长短轴相等函数说明如下BOOLCDC::EllipseintnLeftRectintnTopRectintnRightRectintnBottomRect;其中的参数说明与Rectangle函数相同RoundRect函数用来画圆角矩形,其函数的原型说明如下BOOLCDC::RoundRectintnLeftRectintnTopRectintnRightRectintnBottomRectintnWidthintnHeight;其中的前四个参数与Rectangle函数相同,nWidth表示圆角的宽度nHeight表示圆角的高度Polygon函数用来画封闭的任意多边形,其函数原型说明如下BOOLCDC::PolygonCOUSTPOINT*lpPointsintcCount;其中的参数说明与Polyline函数相同但两个函数有区别,Polygon函数会自动将起点和终点相连形成封闭的多边形,而Polyline函数则画出多条折线,只有当最后一点与起点相同时才画出封闭的多边形示例,绘制矩形、圆角矩形、椭圆和多边形,程序如下//绘制矩形、圆角矩形、椭圆和多边形pDC-Rectangle190270250310;pDC-RoundRect2652703303103020;pDC-Ellipse260-50200-30260+50200+30;POINTpolygonPts
[3]={{390160}{430220}{350210}};pDC-PolygonpolygonPts3;2.2.3画笔与画刷
(1)画笔当绘制图形时,线条的属性,包括颜色、宽度、样式等都是由画笔来确定的程序员可以创建画笔,定义画笔的属性,从而画出多彩的图形创建画笔包括CreatePen和CreatePenIndirect两个函数MFC将这些函数封装在CPen类中,这样画笔就能够被视为对象进行处理下面介绍创建画笔的方法方法一直接构造一个CPen对象,并将定义画笔的参数传给它,例如CPenpenPS-SOLID1RGB25500;创建一个宽度为一个像素、实线和红色的画笔方法二首先声明一个没有初始化的CPen类对象,然后再用CreatePen函数定义画笔的属性例如,CPenPen;Pen-CreatePenPS-SOLID1RGB25500;方法三先声明一个CPen类对象和一个描述画笔结构的LOGPEN类对象,并填入画笔的属性值,然后调用CreatePenIndirect函数来创建画笔如下所示CPenPen;LOGPENLogPen;LogPen.lopnStyle=PS_SOLID;LogPen.lopnWidth=1;LogPen.lpenColor=RGB25500;Pen.CreatePenIndirectLogPen;如果画笔被成功创建,那么两个函数返回TRUE,否则返回FALSE画笔包括样式、宽度和颜色三个属性表2.2列出了GDI画笔的样式表2.2GDI画笔的样式画笔的宽度用像素个数来确定PS_DASH、PS_DOT、PS_DASHDOT和PS_DASHDOTDOT参数要求画笔宽度只能为1,其它参数可以创建任意宽度的画笔画笔的颜色是一个24位的RGB颜色,由RGBrColorgColorbColor来定义,三个参数取值0~255Windows预定义了三个实线、1个像素宽的画笔,它们是WHITE_PEN、BLACK_PEN和NULL_PEN,程序中可以直接使用这些画笔,方法如下CPenPen;Pen.CreateStockObjectWHITE_PEN;示例在屏幕上绘制三组直线,第一组按不同线型绘制,第二组按不同宽度绘制,第三组按不同颜色绘制程序如下//画笔的样式、宽度和颜色inti1;intnPenStyle[]={PS_SOLIDPS_DASHPS_DOTPS_DASHDOTPS_DASHDOTDOTPS_NULLPS_INSIDEFRAME};CPen*pNewPen;CPen*pOldPen;//用不同样式的画笔fori1=0;i17;i1++{//构造新笔pNewPen=newCPen;ifpNewPen-CreatePennPenStyle[i1]1RGB000{pOldPen=pDC-SelectObjectpNewPen;//选择新笔,并保存旧笔//画直线pDC-MoveTo2060+i1*20;pDC-LineTo16060+i1*20;//恢复原有的笔pDC-SelectObjectpOldPen;}else{//出错提示AfxMessageBoxCreatePenErroe!!;}//删除新笔deletepNewPen;}//用不同的宽度的笔绘图fori1=0;i17;i1++{//构造新笔pNewPen=newCPen;ifpNewPen-CreatePenPS_SOLIDi1+1RGB000{pOldPen=pDC-SelectObjectpNewPen;//画直线pDC-MoveTo20060+i1*20;pDC-LineTo34060+i1*20;//恢复原有的笔pDC-SelectObjectpOldPen;}else{//出错提示AfxMessageBoxCreatePenErroe!!;}//删除新笔deletepNewPen;}//设置颜色表structtagColor{intrgb;}color
[7]={{25500}{02550}{00255}{2552550}{2550255}{0255255}{000}};//用不同颜色绘图fori1=0;i17;i1++{//构造新笔pNewPen=newCPen;ifpNewPen-CreatePenPS_SOLID2RGBcolor[i1].rcolor[i1].gcolor[i1].b{pOldPen=pDC-SelectObjectpNewPen;//画直线pDC-MoveTo38060+i1*20;pDC-LineTo52060+i1*20;//恢复原有的笔pDC-SelectObjectpOldPen;}else{//出错提示AfxMessageBoxCreatePenErroe!!;}//删除新笔deletepNewPen;}//画笔程序结束
(2)画刷在进行区域填充或绘制封闭图形时,需要用到画刷MFC把GDI画刷封装在CBrush类中画刷分三种基本类型纯色画刷、阴影画刷和图案画刷纯色画刷绘图使用单色来定义,颜色由RGB函数来确定纯色画刷可以采用直接声明的方法,例如CBrushBrushRGB25500;创建一个红色画刷也可以采用分步方法,由CreateSolidBrush函数创建CBrushBrush;Brush-Create-CreateSolidBrushRGB25500;Windows预定义了七种画刷,包括BLACK_BRUSH、DKGRAY_BRUSH、GRAY_BRUSH、LTGRAY_BRUSH、HOLLOW_BRUSH、NULL_BRUSH和WHITE_BRUSH可以参照CPen类的方法,采用CreateStockObject来使用预定义的画刷阴影画刷使用预定义的六种阴影样式进行绘图表2.3列出了六种阴影样式表2.3六种阴影样式创建阴影画刷的方法与纯色画刷的创建方法相似,例如创建一个45度方向的交叉阴影线的画刷,方法如下CBrushBrushHS_DIAGCROSSRGB25500;或者CBrushBrush;Brush-CreateHatchBrushHS_DIAGCROSSRGB25500;函数中有两个参数,第一个参数是画刷的阴影样式,第二个参数是阴影线的颜色示例绘制缺省画刷的矩形,纯色画刷矩形和绘制100单位的矩形,并且用白色45度交叉线阴影将其填充,程序如下//画刷程序pDC-Rectangle300300400400;//缺省的画刷,白色//纯色画刷CBrush*pNewBrush1;CBrush*pOldBrush1;pNewBrush1=newCBrush;ifpNewBrush1-CreateSolidBrushRGB25500{//选择新画刷pOldBrush1=pDC-SelectObjectpNewBrush1;//绘制矩形pDC-Rectangle200200300400;//恢复原有画刷pDC-SelectObjectpOldBrush1;}deletepNewBrush1;//阴影画刷CBrushBrushHS_DIAGCROSSRGB255255255;CBrush*pOldBrush;pOldBrush=pDC-SelectObjectBrush;pDC-SetBkColorRGB192192192;pDC-Rectangle00100100;pDC-SelectObjectpOldBrush;2.2.4文本显示Windows可以显示很多数据,包括在窗口中显示文本信息由于文本是以图像的形式显示在窗口中的,因此需要处理设备描述表(DC),另外还需要对文本字体的处理,包括文本的显示、文本的颜色、字符的间距和文本的对齐方式等
(1)文本显示在拥有一个设备描述表以后,就可以调用TextOut函数来显示文本行例如pDC-TextOut2020”Thisisalineoftext.”;TextOut函数的三个参数分别是输出文本的X坐标和Y坐标以及输出文本串
(2)设置文本颜色在默认情况下,Windows绘制黑色文本可以通过SetTextColor函数改变文本的颜色例如CDC*pDC=GetDC;//声明一个设备描述表pDC1pDC-SetTextColorRGB25500;//设置文本颜色为红色可以通过GetTextColor函数检索到当前文本的颜色,例如COLORREFcolor=pDC-GetTextColor;SetBkColor和GetBkColor函数用于设置背景颜色和获取当前的背景颜色
(2)设置字符间距SetTextCharacterExtra函数用来设置文本字符的间距,GetTextCharacterExtra用来获得当前文本字符的间距,函数说明如下pDC-SetTextCharacterExtraspace;intspace=pDC-GetTextCharacterExtra;其中,space表示在文本字符之间使用的额外空间的像素数
(3)设置文本的对齐方式SetTextAlign函数用于设置显示文本的对齐方式,函数说明如下pDC-SetTextAlignalignment;其中,alignment参数取值TA_LEFT、TA_CENTER和TA_RIGHT,分别表示左对齐、居中方法和右对齐Alignment参数取值TA_TOP、TA_BOTTOM和TA_BASELINE分别表示文本在垂直方向的对齐方式,上对齐、下对齐和字符的基线对齐2.3鼠标编程在图形操作系统中,鼠标是最重要的输入设备之一Windows系统为用户提供了统一的鼠标编程接口,而不必过多了解其底层的知识Windows是基于消息传递、事件驱动的操作系统,当用户移动鼠标、按下或释放鼠标键时都会产生鼠标消息应用程序可以接收10种鼠标消息,表2.3列出了这些鼠标消息和它们的描述表2.3鼠标消息和描述2.2.1鼠标消息处理MFC把鼠标消息处理函数封装在CView类中,它们分别是OnMouseMoveUINTnFlagsCPointpoint;OnLButtonDblclkUINTnFlagsCPointpoint;OnLButtonDownUINTnFlagsCPointpoint;OnLButtonUpUINTnFlagsCPointpoint;……分别对应表2.3中10个鼠标消息在鼠标处理函数中,point参数代表鼠标热点处的坐标位置,point.x为横坐标,point.y为纵坐标默认坐标原点(0,0)位于窗口的左上角由于应用程序要求自动捕获鼠标事件,因此应当采用Windows事件处理函数,而不是成员函数,具体使用方法参见2.2.3节示例程序nFlags参数中包含了鼠标按钮和键盘组合使用标志,用来描述鼠标按钮和键盘上的Shift键和Ctrl键的组合状态nFlag参数取值范围MK_LBUTTON鼠标左键被按下;MK_RBUTTON鼠标右键被按下;MK_MBUTTON鼠标中键被按下;MK_SHIFT键盘上的Shift键被按下;MK_CONTROL键盘上的Ctrl键被按下;如果想知道某个键是否被按下,可用对应的位屏蔽值与nFlags参数作按位逻辑“与”运算,所的结果若为非零值,则表示该按钮被按下,例如ifnFlagsLBUTTONAfxMessageBox“LButtonispresseddown!”ElseAfxMessageBox“LButtonispressedUp!”;如何区分两次单击和一次双击,这取决于两次按下按钮之间的时间间隔,只有当时间间隔小于一定值时才被认为是一次双击Windows默认的时间为500ms可以用SetDoubleClickTime函数来重新设置时间间隔值若要使窗口函数能接收到鼠标双击产生的消息,在注册窗口类时,必须指明该窗口具有CS_DBLCLKS风格,否则,即使进行了双击操作,该窗口也只能收到两条“WM_LBUTTONDOWN”和“WM_LBUTTONUP”消息,例如wndclass.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;2.2.2捕捉鼠标在交互式图形程序设计中,经常要使用鼠标的位置拾取、拖动或拖放,这些动作必须进行鼠标的捕捉鼠标捕捉只需要调用CWnd::SetCapture函数用户完成鼠标捕捉工作后一般是响应一个鼠标按下信息,要释放鼠标捕捉则是调用CWnd::ReleaseCapture函数释放被捕捉鼠标的最好时间是在响应鼠标弹起的时候(WM_LBUTTON)2.2.3鼠标编程综合示例示例1在窗口中以文本的形式给出鼠标的状态,即当鼠标移动时,给出鼠标的位置;当鼠标按下鼠标左、右键时显示出鼠标按键状态例如,当鼠标左键按下时,显示“LBUTTONDOWN!”第一步建立一个myMouse工程文件;第二步添加鼠标事件处理函数鼠标右击视图类(如CmyMouseView),选择“addwindowsmessagehandler…”,弹出事件处理函数列表窗口,如图3-11所示图3-11Windows事件处理函数列表窗口从左边事件消息列表中选择“WM_LBUTTONDOWN”,然后单击“AddandEdit”按钮,即加入鼠标左键按下事件函数,并要求编辑事件处理程序第三步输入事件处理程序voidCMymouseView::OnLButtonDownUINTnFlagsCPointpoint{//TODO:Addyourmessagehandlercodehereand/orcalldefault//获得pDCCDC*pDC=GetDC;pDC-TextOut2040”LBUTTONDOWM!”;//输出显示信息CView::OnLButtonDownnFlagspoint;}其中,阴影部分是用户输入的程序,其它内容都是自动生成的内容第四步重复第二步和第三步,分别添加WM_LBUTTONUP,WM_MOUSEMOVE,WM_RBUTTONDOWN,WM_RBUTTONUP,WM_LBUTTONDBCLK,WM_RBUTTONDBCLK鼠标事件,并输入以下程序voidCMouseView::OnLButtonUpUINTnFlagsCPointpoint{//TODO:Addyourmessagehandlercodehereand/orcalldefaultCDC*pDC=GetDC;pDC-TextOut2040LButtonUP!;CView::OnLButtonUpnFlagspoint;}voidCMouseView::OnRButtonDownUINTnFlagsCPointpoint{//TODO:Addyourmessagehandlercodehereand/orcalldefaultCDC*pDC=GetDC;pDC-TextOut2060RButtonDown!;CView::OnRButtonDownnFlagspoint;}voidCMouseView::OnRButtonUpUINTnFlagsCPointpoint{//TODO:Addyourmessagehandlercodehereand/orcalldefaultCDC*pDC=GetDC;pDC-TextOut2040RButtonUP!;CView::OnRButtonUpnFlagspoint;}voidCMouseView::OnMouseMoveUINTnFlagsCPointpoint{//TODO:Addyourmessagehandlercodehereand/orcalldefaultCDC*pDC=GetDC;chartbuf
[80];sprintftbufPosition:%3d%3dpoint.xpoint.y;//输出鼠标当前位置pDC-TextOut2020tbuf;CView::OnMouseMovenFlagspoint;}voidCMouseView::OnLButtonDblClkUINTnFlagsCPointpoint{//TODO:Addyourmessagehandlercodehereand/orcalldefaultCDC*pDC=GetDC;pDC-TextOut2080LButtonisdoubleclicked!;CView::OnLButtonDblClknFlagspoint;}voidCMouseView::OnRButtonDblClkUINTnFlagsCPointpoint{//TODO:Addyourmessagehandlercodehereand/orcalldefaultCDC*pDC=GetDC;pDC-TextOut2080RButtonisdoubleclicked!;CView::OnRButtonDblClknFlagspoint;}第五步编译程序,并验证执行结果示例2采用鼠标橡皮筋技术画圆鼠标橡皮筋技术画圆就是采用圆心和圆周上任一点画圆技术(简称C+P方法),首先用鼠标左击选择圆心位置,然后移动鼠标,圆随鼠标移动而扩大或缩小,当再次单击鼠标左键时,确定圆周上的一点,从而画出相应的圆直线、矩形等基本图形都可以采用橡皮筋技术第一步建立MouseSpring工程文件;第二步向视图类中添加自定义的成员变量用鼠标右键单击视图类,选择“AddMemberVariable…”添加下面三个成员变量proctected:CPointm_bO;//圆心CPointm_bR;//圆上的点intm_ist;//圆心与圆周上点的区别,m_ist=0,表示鼠标左击点为圆心,//m_ist=1,表示鼠标左击点为圆周上的点操作方法如图3-13所示,分别添加上述三个成员变量图3-13添加成员变量第三步向视图类中添加自定义的成员函数原型public:voidDrawCircleCDC*pDCCPointcenpCPointardp;intComputeRadiusCPointcenpCPointardp;具体操作方法用鼠标右键单击视图类,选择“AddMemberFunction…”,如图3-14所示分别添加上述两个成员函数,分别用于画圆和计算圆的半径图3-14添加成员函数第三步在视图类CPP文件的构造函数中初始化成员变量视图类的构造函数名与该视图类的名字相同在视图类中选择构造函数,如CMouseSpringView,用鼠标左键双击,输入下面程序代码CMouseSpringView::CMouseSpringView{//TODO:addconstructioncodeherem_bO.x=0;m_bO.y=0;//圆心m_bR.x=0;m_bR.y=0;//圆上的点m_ist=0;//圆心与圆上的点区别}第四步在视图类的OnDraw函数中加入下列代码,实现视图绘图voidCMouseSpringView::OnDrawCDC*pDC{CMouseSpringDoc*pDoc=GetDocument;ASSERT_VALIDpDoc;//TODO:adddrawcodefornativedataherepDC-SelectStockObjectNULL_BRUSH;DrawCirclepDCm_bOm_bR;//调用自定义的成员函数画圆}第五步向视图类中添加两个鼠标消息响应函数,并输入鼠标处理程序代码具体操作方法与鼠标示例1方法相同一个是OnLButtonDown函数,另一个是OnMouseMove函数程序如下voidCMouseSpringView::OnLButtonDownUINTnFlagsCPointpoint{//TODO:Addyourmessagehandlercodehereand/orcalldefaultCDC*pDC=GetDC;pDC-SelectStockObjectNULL_BRUSH;if!m_ist//绘制圆{m_bO=m_bR=point;//纪录第一次单击鼠标位置,定圆心m_ist++;}else{m_bR=point;//记录第二次单击鼠标的位置,定圆周上的点m_ist--;//为新绘图作准备DrawCirclepDCm_bOm_bR;//绘制新圆}ReleaseDCpDC;//释放设备环境CView::OnLButtonDownnFlagspoint;}voidCMouseSpringView::OnMouseMoveUINTnFlagsCPointpoint{//TODO:Addyourmessagehandlercodehereand/orcalldefaultCDC*pDC=GetDC;intnDrawmode=pDC-SetROP2R2_NOT;//设置异或绘图模式,并保存原来绘图模式pDC-SelectStockObjectNULL_BRUSH;ifm_ist==1{CPointprePntcurPnt;prePnt=m_bR;//获得鼠标所在的前一位置curPnt=point;//绘制橡皮筋线DrawCirclepDCm_bOprePnt;//用异或模式重复画圆,擦出所画的圆DrawCirclepDCm_bOcurPnt;//用当前位置作为圆周上的点画圆m_bR=point;}pDC-SetROP2nDrawmode;//恢复原绘图模式ReleaseDCpDC;//释放设备环境CView::OnMouseMovenFlagspoint;}第六步添加成员函数的程序代码分别为两个成员函数DrawCircle和ComputeRadius添加程序代码,程序如下voidCMouseSpringView::DrawCircleCDC*pDCCPointcenpCPointardp{intradius=ComputeRadiuscenpardp;//由圆心确定所画圆的外切区域CRectrccenp.x-radiuscenp.y-radiuscenp.x+radiuscenp.y+radius;pDC-Ellipserc;//画出一个整圆}intCMouseSpringView::ComputeRadiusCPointcenpCPointardp{intdx=cenp.x-ardp.x;intdy=cenp.y-ardp.y;//sqrt函数的调用,在头文件中加入#includemath.hreturnintsqrtdx*dx+dy*dy;}第七步编译运行程序,验证运行结果2.4菜单程序设计在Windows应用程序设计中,菜单是重要的用户界面对象和交互手段Windows支持三种类型的菜单,他们分别是菜单栏(主菜单)、弹出式菜单和上下文菜单(单击鼠标右键弹出的浮动菜单)本节主要介绍如何对菜单进行编辑、如何响应菜单的消息、如何运用菜单的UI机制、如何动态地改变菜单以及如何处理上下文菜单2.
4.1菜单编辑器菜单编辑器用来创建并编辑菜单资源,是一个可视化设计工具对于MDI应用程序(多文档应用程序),AppWizard自动生成两个菜单资源IDR_MAINFRAME和IDR_PrjNameTYPEPrjName是应用程序工程名在MDI子窗口打开之前系统显示IDR_MAINFRAME菜单,在MDI子窗口打开之后系统显示IDR_PrjNameTYPE菜单对于SDI应用程序,AppWizard只生成一个菜单资源IDR_MAINFRAME在一个SDI文档工程项目中,在工作区窗口种选择ResourceView标签,列出工程项目的所有资源,选择Menu,双击IDR_MAINFRAME,弹出菜单编辑器窗口,如图3-15所示图3-15菜单编辑器
(1)创建菜单和菜单选项在图3-15中,可以创建主菜单,也可以创建菜单选项可以通过Tab键(向右移)、Shift+Tab键(向左移),或鼠标定位,通过Ins键在某一菜单前插入新的菜单另外,用鼠标拖动菜单方框可以改变菜单项的相对位置例如,在查看菜单前插入一个“绘图”菜单,包括直线、圆、矩形和颜色四个菜单项步骤1定位到“查看”菜单,按下Ins键或Insert键,插入一个空菜单项;通过Delete键删除一个菜单项;步骤2双击空菜单项,弹出菜单项对话框,并输入菜单信息,如图3-16所示图3-16菜单对话框步骤3添加菜单项条目双击“绘图”菜单下的空菜单项,弹出菜单项对话框如图3-17所示图3-17菜单项对话框步骤4重复第3步,完成菜单设计在菜单设计中,可以为菜单或菜单项定义助记符,方法是在响应的字符前加符号菜单项的ID号,可以选取已有的ID号,也可以自定义ID号,如果不输入ID号,则系统自动生成一个ID号另外,在菜单项对话框中还可以为菜单项指定风格另外,还可以为菜单项定义快捷键,方法是在标题后直接输入,转义符\t表示快捷键左对齐弹出菜单的设计弹出菜单就是主菜单项的子菜单,也称为级联菜单创建级联菜单的方法如下选择级联菜单项,在该菜单项属性对话框中选中“弹出”(Pop-up)复选项,于是该项便被标记级联菜单符(►),且在该项的右侧出现新的菜单项空方框添加级联菜单项的方法与上述方法相同如图3-18所示图3-18级联菜单设计
(3)上下文菜单单击鼠标右键将弹出相应的上下文菜单为了在应用程序中使用上下文菜单,首先要创建菜单本身,然后将其与应用程序代码链接创建上下文菜单的步骤如下步骤1创建带空标题的菜单栏右击Menu,选择“Insert”创建一个空的菜单栏;步骤2输入菜单标题和菜单项,并保存菜单资源,默认为IDR_MENI1;步骤3在源文件中添加下列程序代码CMenumenu;//装载并验证菜单资源;VERIFYmenu.LoadMenuIDR_MENU1;CMenu*pPopup=menu.GetSubMenu0;ASSERTpPopup!=NULL;//显示菜单内容pPopup-TrackPopupMenuTPM_LEFTALIGN|TPM_RIGHTBUTTONxyAfxGetMainWnd;在创建上下文菜单资源后,应用程序代码装载菜单资源并使用函数TrackPopupMenu来显示菜单内容2.
4.2菜单消息响应Windows应用程序是通过消息传递机制运行的为菜单项添加相应功能函数的方法步骤步骤1右击所选菜单项,从弹出的菜单中选择“建立类向导…”,弹出类向导对话框,如图3-19所示;图3-19建立类向导对话框步骤2选择工程名(Project:),并在类名(Classname:)中选择视图类,在ObjectIDs:列表中选择菜单项的ID号,在Messages:列表中选择COMMAND;步骤3单击“AddFunction…”,添加成员函数;步骤4选择该成员函数,单击“EditCode”输入或编辑程序代码2.
4.3综合示例利用菜单资源编辑器在默认的菜单中添加“字体”菜单项在程序运行过程中改变菜单项的显示状态步骤1创建Mymenu应用程序工程文件,选择单文档应程序;步骤2利用ResourceView设计菜单,如图3-20所示;图3-20菜单设计示例步骤3在CMymenuView视图类中添加消息映射函数;添加方法选择View\ClassWizard菜单项,弹出如图3-19所示的创建类对话框,从中选择工程名(Projects)和类名(Classname),并从ObjectIDs列表框中选择ID_FONTCOLOR1项,在Messages列表框中选择COMMAND,然后,单击“AddFunction”按钮,弹出加入成员函数的对话框,输入成员函数名OnFontcolor1,确定后就添加了OnFontcolor1消息映射函数参照以上方法,添加上表中其他的函数步骤4在CMymenuView类中添加成员变量和成员函数方法参见鼠标编程中的示例2,在CMymenuView类中添加上述的成员变量和成员函数步骤5编写CTestMenuView::CMymenuView构造函数CTestMenuView::CTestMenuView{//TODO:addconstructioncodeherem_FontColor=RGB000;//设置默认的颜色}步骤6编写CMymenuView::OnDraw函数voidCTestMenuView::OnDrawCDC*pDC{CTestMenuDoc*pDoc=GetDocument;ASSERT_VALIDpDoc;//TODO:adddrawcodefornativedatahereRedrawpDC;}步骤7分别编写步骤3添加的3个函数,程序如下voidCMymenuView::OnFontcolor1{//TODO:Addyourcommandhandlercodeherem_FontColor=RGB25000;CDC*pDC=GetDC;RedrawpDC;}voidCMymenuView::OnFontcolor2{//TODO:Addyourcommandhandlercodeherem_FontColor=RGB02500;CDC*pDC=GetDC;RedrawpDC;}voidCMymenuView::OnFontcolor3{//TODO:Addyourcommandhandlercodeherem_FontColor=RGB00250;CDC*pDC=GetDC;RedrawpDC;}步骤8编写CTestMenuView::Redraw函数voidCMymenuView::RedrawCDC*pDC{//设置文本颜色,显示测试内容pDC-SetTextColorm_FontColor;pDC-TextOut3030菜单测试程序!;}步骤9编译和运行程序,查看程序运行结果函数描述使用频率Arc椭圆弧****BitBlt把位图从一个DC拷贝到另一个DC*Draw3dRect绘制三维矩形**DrawDragRect绘制用鼠标拖动的矩形**DrawEdge绘制矩形的边缘**DrawIcon绘制图标***Ellipse绘制椭圆****FillRect绘制用给定的画刷颜色填充矩形***FillRgn绘制用给定的画刷颜色填充区域***FillSolidRed绘制用给定的颜色填充矩形***FloodFill用当前的画刷颜色填充区域***FrameRect绘制矩形边界**FrameRgn绘制区域边界**GetBKColor获取背景颜色*****GetCurrentBitmap获取所选位图的指针**GetCurrentBrush获取所选画刷的指针***GetCurrentFont获取所选字体的指针***GetCurrentPalette获取所选调色板的指针***GetCurrentPen获取所选画笔的指针***GetCurrentPosition获取画笔的当前位置****GetDeviceCaps获取显示设备能力的信息**GetMapMode获取当前设置映射模式***Getpixel获取给定像素的RGB颜色值*****GetPolyFillMode获取多边形填充模式***GetTextColor获取文本颜色****GetTextExtent获取文本的宽度和高度**GetTextMetrics获取当前文本的信息**GetWindow获取DC窗口的指针**GrayString绘制灰色文本***LineTo绘制直线******MoveTo设置当前画笔位置******Pie绘制饼图***Polygon绘制多边形***PolyLine绘制一组直线***RealizePalette将逻辑调色板映射到系统调色板**Rectangle绘制矩形****RoundRect绘制圆角矩形***SelectObject选择GDI绘图对象**SelectPalette选择逻辑调色板**SelectStockObject选择预定义图形对象**SetBkColor设置背景颜色******SetMapMode设置映射模式***SetPixel把像素设定为给定的颜色******SetTextColor设置文本颜色******StretchBlt把位图从一个DC拷贝到另一个DC,并根据需要扩展或压缩位图*TextOut绘制字符串文本*****样式说明PS_SOLID创建实线笔PS_DASH创建虚线笔,只有当画笔宽度小于或等于1时有效PS_DOT创建点线笔,只有当画笔宽度小于或等于1时有效PS_DASHDOT点划线笔,只有当画笔宽度小于或等于1时有效PS_DASHDOTDOT双点划线笔,只有当画笔宽度小于或等于1时有效PS_NULL创建NULL笔,不绘制任何图形PS_INSIDEFRAME创建可以在封闭框架内部绘制直线的画笔阴影样式说明HS_BDIAGONAL45度向下阴影线(从左到右)HS_CROSS水平线与垂直线交叉阴影HS_DIAGCROSS45度方向的交叉阴影线HS_FDIAGONAL45度向上阴影线(从左到右)HS_HORIZONTAL水平阴影线HS_VERTICAL垂直阴影线消息描述WM_LBUTTONDBLCLK鼠标左键被双击WM_LBUTTONDOWN鼠标左键被按下WM_LBUTTONUP鼠标左键被释放WM_MBUTTONDBLCLK鼠标中键被双击WM_MBUTTONDOWN鼠标中键被按下WM_MBUTTONUP鼠标中键被释放WM_MOUSEMOVE鼠标移动穿过对象区域WM_RBUTTONDBLCLK鼠标右键被双击WM_RBUTTONDOWN鼠标右键被按下WM_RBUTTONUP鼠标右键被释放菜单菜单项选项格式(S)颜色(C)Pop-up=Checked格式(S)字体IPop-up=Checked菜单菜单项ID值提示(Prompt)颜色(C)红色ID_FONTCOLOR1红色字体颜色(C)绿色ID_FONTCOLOR2绿色字体颜色(C)蓝色ID_FONTCOLOR3蓝色字体对象消息函数ID_FONTCOLOR1COMMANDOnFontcolor1ID_FONTCOLOR2COMMANDOnFontcolor2ID_FONTCOLOR3COMMANDOnFontcolor3变量类型变量名称访问权限COLORREFm_FontColorprotectedvoidRedrawCDC*pDCprotected。