C++屏幕绘图

bnwe 贡献于2016-01-31

作者 龙  创建于2011-03-02 09:20:00   修改者Administrator  修改于2011-03-02 10:39:00字数18659

文档摘要:第7章屏幕绘图及文本显示屏幕是最基本的输出设备,屏幕绘图及文本显示是应用程序最常用的功能,本章讲述VisualC++中屏幕绘图及文本显示的工作原理及其基本编程方法。首先介绍GDI与设备描述表,然后介绍CDC类、映射方式等概念,最后介绍基本的绘图函数及文本显示函数的用法。
关键词:

 第7 章屏幕绘图及文本显示 屏幕是最基本的输出设备,屏幕绘图及文本显示是应用程序最常用的功能,本章讲述VisualC ++中屏幕绘图及文本显示的工作原理及其基本编程方法。首先介绍GDI与设备描述表,然后介绍CDC类、映射方式等概念,最后介绍基本的绘图函数及文本显示函数的用法。 7.1 GDI与设备描述表 Windows 操作系统是一个图形界面的操作系统,为了方便地在屏幕上和打印机上绘制或输出图形与文本,Windows 系统中为用户提供了设备描述表和GDI 函数来实现应用程序与物理设备间的接口。 7.1.1 GDI的基本概念 Windows图形设备接口GDI(Graphical Device Interface)是为与设备无关的图形设计的。所谓设备的无关性,就是操作系统屏蔽了硬件设备的差异,因而设备无关性能使用户编程时无需考虑特殊的硬件设置。 Windows把与绘图工作相关的操作都制作成了函数,GDI提供了用户可以调用的一套用于绘图的函数集。无论基础硬件如何,同一函数都能够生成相同结果。例如,调用GDI函数中的Ellipse函数可以绘制椭圆,调用TextOut函数可以绘制文本,调用Rectangle函数可以绘制矩形等。 除了这些绘图函数之外,GDI还有一套用于绘图的工具(对象),比如画刷、画笔等。GDI绘图工具的使用在7.4小节中介绍。 文本被看作是图形,这种处理方式虽然在创建文本输出时增加了复杂度,但也增强了灵活性。可以让原本在文本世界非常困难的工作变得非常轻松。 7.1.2设备描述环境 Windows下,有多种输出设备,如各种显示器、打印机、绘图仪等。由于用来显示图形的实际物理设备的多样性,因此要求程序设计人员具有对所有图形显示设备的编程能力是不现实的。为了简化应用这些性质不同的设备的访问,实现与设备无关的绘图操作,Windows 提供了一种叫做设备描述表的机制,也称为设备环境DC(Device Context),它是Windows 应用程序与设备驱动程序和输出设备(如打印机、显示器等)之间的接口,用来作为应用程序与控制输出设备的低层之间的通道。设备描述表是一种可以在其上绘图的“逻辑画布”,它接收应用程序的绘图命令,再将其翻译为控制设备驱动程序的低层指令。程序员可以在这个虚拟的图形显示对象上进行绘图,而把这个图形最终转换为实际物理设备上图形的工作则交给系统去完成。这样,通过设备描述符表机制,程序可以独立于“真实”的硬件。 设备环境DC(Device Context)是由GDI保存的一个数据结构,设备环境包含了输出设备的绘图特征,不同设备有不同的设备环境,在输出设备上输出的先决条件是获得该设备的设备环境。例如,为了在屏幕上显示绘图,Window程序必须有该显示器的一个DC。为了在打印机输出,还需要另一个专门为打印机创建的DC。 Windows 中的设备描述表分为以下4 种类型。 显示器型:支持显示器上的绘图操作。 打印机型:支持打印机和绘图仪上的绘图操作。 内存型:支持位图上的绘制操作。 信息型:支持设备数据的访问。 为了方便,Windows系统初始化了一套DC的属性和对象,表7-1为显示器DC的属性及默认值,获得了该设备的DC后,程序设计人员就可以在这个默认的环境下开始绘图工作了。当然,如果程序员对预置的属性和对象不满意的话,也可以按自己的要求对它们进行设置。例如,默认的DC中预置了一支黑色画笔,所以这时用GDI的绘图函数绘制的任何线条都是黑色的。如果想使用其他颜色绘制线条的话,程序员可以用其他颜色的画笔来替换这支黑色的画笔。DC在任何时候总是必须存在着一套完整的绘图工具。这意味着,不能从DC中删除一个工具,只能用一个工具替换另一个工具。绘图过程可描述为使用GDI 对象(逻辑画笔或画刷等)在设备描述表(逻辑画布)上绘制的过程。 表7-1显示器DC的属性及默认值 属性 默认值 背景色 WHITE 背景模式 OPAQUE 位图 NONE 画刷 WHITE_BRUSH 画刷起始位置 (0,0) 剪截域 DISPLAY SURFACE 颜色调色板 DEFAULT_PALETTE 绘图方式 R2_COPYPEN 字体 SYSTEM_FONT 字符间距 0 映射方式 MM_TEXT 画笔 BLACE_PEN 多边形填充方式 ALTERNATE 缩放模式 BLACKONWHITE 文本颜色 BLACK 试图范围 (1,1) 视图原点 (0,0) 窗口范围 (1,1) 窗口原点 (0,0) 7 . 2CDC 类 MFC的CDC类对设备描述表和GDI 函数进行了全面的封装,使这两者的使用更加方便。CDC 类是一个通用的类,可以从它派生出特定类型的DC子类。 1、CDC 类的成员函数 由于DC 与屏幕绘图及文本显示操作密切相关,CDC 类的成员函数主要包括以下几类: 初始化函数,比如为指定的设备创建设备描述符表等。 设备描述符表函数,比如保存或恢复DC的状态等。 绘图及其相关函数,比如设置绘图前景颜色、背景颜色、绘图工具选择、图形绘制等。 文本与字体函数,比如文本输出、字体信息的取得等。 坐标与映射函数,比如设置映射方式、各种坐标的转换等。 具体函数用法在7.6小节中介绍。 2、几种派生的CDC类 几种派生的CDC类如表7-2所示 表7-2几种派生的CDC类 类名 说明 CClientDC 在相应除WM_PAINT消息之外的消息处理函数中,提供窗口客户区的设备描述环境。 CMetaFileDC 代表Windows图元文件的设备描述环境。在创建与设备无关的并且可以回放的图像时使用这个类型的DC。 CPaintDC 在OnDraw()函数中使用的窗口用户区的设备描述环境。在MFC中用OnDraw()来处理WM_PAINT消息。 CWindowDC 提供在整个窗口内(不只是用户区)绘图的设备描述环境。 CPaintDC是所有CDC类中最常用的一个类,它代表了应用程序窗口的客户区,它只能使用在CView类的OnDraw函数中。OnDraw函数的声明为: OnDraw(CDC*pDC); 对应用程序窗口的客户区进行绘图的所有代码都必须写在这个函数中。应用程序窗口在每次创建及需要刷新时就会产生WM_PAINT消息,如用户区移动或显示,用户窗口大小改变,程序通过滚动条滚动窗口,窗口被另一个窗口覆盖的恢复,还有下拉式菜单关闭等,这些情况下就会发送WM_PAINT消息。系统接收到这个消息就会自动调用OnDraw函数。这个函数的参数pDC就是指向CPaintDC对象的指针,在OnDraw的函数体中,就可以通过这个指针来使用DC类的成员函数进行绘图操作了。 例7_1在用户区显示字符串“Hello World”。 ①用MFCAppwizard创建一个名称为ex7_1的单文档应用程序框架。 ②在视图类中的OnDraw函数中添加语句:pDC->Textout(50,50, “HELLO ”),即视图类的代码为: void CEx7_1View::OnDraw(CDC *pDC) { CEx7_1Doc *pDoc=GetDocument(); ASSERT_VALID(pDoc); //TODO : add draw code for native data here pDC->TextOut(50,50,"HELLO");//输出字符串的语句 } 程序运行结果如图7-1所示。 对于WM_PAINT 消息的响应,框架代码已经做了大量的工作,已经自动处理了DC的申请与释放的问题,用户所要做的只是在OnDraw()函数内完成绘图工作即可。下面的几节中,主要是在CPaintDC中绘图。 图7-1 例7-1程序的运行结果图 7.3 映射模式 映射模式是设备描述符表DC 的一个重要属性,它影响到GDI 绘图及文本的显示效果。 7 .3. 1 设备坐标 图形或文字要在物理设备(如显示器、打印机等)上输出,就必须使用该物理设备的坐标系统,称为设备坐标。设备坐标以设备的最小分辨单位——像素为基本单位,以左上角为坐标原点,X 轴向右延伸,Y 轴向下延伸,如图7-2所示。 图7-2设备坐标系 最常用的设备坐标就是屏幕的设备坐标,这里面又包含几种具体的设备坐标系。若以整个屏幕为范围,就是“屏幕坐标系统”,像WM_MOVE消息这样不依赖于窗口的消息,必须以整个屏幕为参照物,使用的是屏幕坐标。若以整个窗口为基准,将标题栏、菜单、滚动条、窗口边框等均计算在内,这种坐标称为“窗口坐标系统”,一般情况下窗口坐标较少使用。若以窗口的用户区为范围,点(0 , 0 )位于用户区的左上角,这种坐标称为用户区坐标,这是最常用的一种设备坐标。函数ClientToScreen( )和ScreenToClient ( )可以将用户区坐标转换为屏幕坐标,或者将屏幕坐标转换为用户区坐标。 7 . 3. 2 逻辑坐标 如果直接使用设备坐标绘图,由于屏幕和打印机的分辨率不同,同样是100个像素长的一条直线,在两种设备上的实际输出长度将不相同。假设程序员想画一条在两种设备上都是10 cm长的直线,将不得不针对屏幕和打印机的分辨率分别计算它们各需要包含多少个设备像素。为了解决这个问题,在GDI 绘图中使用了逻辑坐标这一概念。逻辑坐标使用的是逻辑单位,逻辑单位与设备无关,比如逻辑单位是0.lmm ,则一条100 个逻辑单位长的直线,不论是显示在屏幕上,还是输出到打印机上,都是10cm 长。虽然最终显示或打印时仍然要使用像素点(设备坐标),但一个逻辑单位应该映射为物理设备上的多少个像素点,是由Windows 自动处理的。 本章后面几小节介绍的GDI 绘图函数使用的都是逻辑坐标。 7 . 3. 3 映射模式 映像模式定义了将逻辑单位转化为设备的度量单位的方法以及设备的X方向和Y方向,程序员可在一个统一的逻辑坐标系中操作而不必考虑输出设备的坐标系情况。映射模式对应用程序是很重要的。Windows 中定义了8 种映射模式,如表7-3所示。 表7-3 映射模式 映射模式 将一个逻辑单位映射为 X轴增长方向 Y轴增长方向 MM_TEXT 1像素 向右 向下 MM_LOMETRIC 0.1毫米 向右 向上 MM_HIMETRIC 0.01毫米 向右 向上 MM_LOENGLISH 0.01英寸 向右 向上 MM_HIENGLISH 0.001英寸 向右 向上 MM_TWIPS 1/1440英寸 向右 向上 MM_ISOTROPIC 任意(X=Y) 可选 可选 MM_ANISOTROPIC 任意(X!=Y) 可选 可选 MM _ TEXT 是最简单的一种映射模式,也是默认的映射模式,它使得逻辑坐标完全等价于设备坐标。其他几种映射模式下,逻辑坐标的原点也位于窗口的左上角,但对于Y 轴是向下增长的。 MM_ANISOTROPIC和MM_ISOTROPIC这两种映射模式通过将图形从程序员定义的逻辑坐标窗口映射到物理设备的视口以实现坐标转换。窗口是对应逻辑坐标系上程序员设定的区域,视口是对应实际输出设备上程序员设定的区域。这两种映射模式的区别是MM_ANISOTROPIC按照窗口和视口的坐标比例进行映射,而MM_ISOTROPIC将窗口中的对称图形映射到视口时仍为对称图形。在MM_ISOTROPIC映射模式下,圆总是圆的,但是在MM_ANISOTROPIC映射模式下,圆可以被拉扁成椭圆形状。 1、映射模式的设置 要改变DC的映射模式,可以使用CDC类的SetMapMode( )函数,函数原型形为: virtual int SetMapMode ( int nMapMode); 参数nMapMode 是新设置的映射模式,函数的返回值是DC先前的映射模式。 若要取得DC 当前的映射模式,可以使用CDC类的函数GetMapMode( ),函数原型形为: int GetMapMode ( ) const ; 此函数的返回值是当前的映射模式。 例7-2将“Hello World”显示在离客户区左边和上边各l 英寸的地方。 ①用MFCAppwizard创建一个名称为ex7_2的单文档应用程序框架。 ②在视图类中的OnDraw函数中添加语句,添加后的代码为: void CEx7_2View::OnDraw(CDC *pDC) { CEx7_2Doc *pDoc=GetDocument(); ASSERT_VALID(pDoc); //TODO : add draw code for native data here pDC->SetMapMode(MM_LOENGLISH) ; pDC->Textout (100 ,-100 , “Hello World” ) ; //输出字符串的语句 } 2、设置窗口和视口的大小 窗口区域的定义由SetWindowExtEx函数完成,其函数原型为: BOOL SetWindowExtEx ( int nHeight //以逻辑单位表示的窗口区域高度 int nWidth, //以逻辑单位表示的窗口区域宽度 LPSIZE lpSize, //函数调用前窗口区域尺寸的SIZE结构地址 ); 视口区域的定义由SetViewportExtEx函数完成,函数原型为: BOOL SetViewportExtEx ( int nHeight //以逻辑单位表示的视口区域高度 int nWidth, //以逻辑单位表示的视口区域宽度 LPSIZE lpSize //函数调用前视口区域尺寸的SIZE结构地址 ); 设置窗口和视口的大小只有在映射模式为MM_ANISOTROPIC和MM_ISOTROPIC时才有意义。 7 . 4 绘图工具的使用 Windows 提供了一些工具用于绘图,这些工具有:画笔(Pen)、画刷(Brush)、位图( Bitmap)、字体(Font)、调色板(Palette)、区域(Region)等,这些都称为GDI 对象。 7 . 4. 1 GDI绘图工具介绍 ( l )画笔:画笔是一种用来画线或有形边框的工具,可以指定它的颜色及宽度,也可以指定线型(实线、点线、虚线等)。 ( 2 )画刷:画刷(或称为刷子)定义了一种位图形式的像素模板,利用它可以对区域内部填以颜色。 ( 3 )位图:位图定义了每个显示像素的颜色,可以用来表示图像,以及图标、光标、刷子等的形状。 ( 4 )字体:字体是一种具有某种风格和尺寸的所有字符的完整集合,它常常被当作资源存在磁盘中。字体用来控制文字的显示。 ( 5 )调色板:调色板是一种颜色映射表,利用它可以使应用程序最大可能地使用输出设备的颜色输出能力,而无须严重于扰其他程序使用的颜色。 ( 6 )区域:区域由位于一个窗口内的椭圆或多边形组合而成,可以用来进行填充、剪裁以及鼠标选中测试等。 MFC 中用CPen 类封装了Windows 的画笔、用CBrush 类封装了Windows 的画刷、用CBitmap即类封装了Windows 的位图、用CFont 类封装了Windows 的字体、用CPalette 类封装了Windows 的调色板、用CRgn 类封装了Windows 的区域。 7 . 4 . 2 画笔 画笔是绘图的基本工具,在MFC中画笔是CPen类的对象,它可以用来完成各种画线条的任务。DC在初始化时,就自动配备了一个黑色的默认画笔。如果程序设计人员对这个默认的画笔不满意,要改变线的颜色、粗细、线型等属性需要创建新的画笔对象,并将其载入DC中以取代默认的画笔即可。 一、创建画笔 创建画笔有两种方法:一步构造法和二步构造法。 1、一步构造法 利用CPen 类的带参构造函数来完成画笔对象的创建及初始化。CPen 类的带参构造函数有两个重载版本,下面介绍最常用的一个。 CPen ( int nPenstyle , int nWidth , COLORREF crColor ) ; 参数nPenstyle 指定画笔的风格,表7-4中列出了最常用的取值。 表7-4画笔的样式 样式 说明 PS_SOLID 画实线 PS_DASH 画虚线 PS_DOT 画点线 PS_DASHDOT 画点划线 PS_DASHDOTDOT 画双点划线 PS_NULL 不可见的画笔 PS_INSIDEFRAME 在一个图形内画边划线的画笔 参数nwidth 指定笔的宽度。 参数crColor用来以RGB值设置画笔的颜色。 Windows定义的一个用红、绿、蓝分色定义颜色的宏: RGB COLORREF RGB( BYTE bRed, //红色(0~255) BYTE bGreen,//绿色(0~255) BYTE bBlue //蓝色(0~255) ); 例如: RGB ( 0, 0 , 0 ) / /黑色 RGB ( 255 , 0 , 0 ) / /红色 RGB ( 255 , 255 , 255 ) / /白色 RGB ( 128 , 128 , 128 ) / / Windows 里的标准灰色 CPen Penl ( PS_DASH , 5 , RGB ( 255 , 0 , 0 ) ) ; / /创建5 个单位粗、红色、虚线的画笔 2、二步构造法 首先用CPen 类的无参构造函数构造CPen 类的对象,然后调用CPen 类的CreatePen( )或CreatePenIndirect( )函数初始化画笔对象。下面介绍CreatePen( )函数,此函数有两个重载版本,最常用的版本如下: BOOL CreatePen ( int nPenstyle , int nWidth , COLORREF crColor ) ; 参数:nPenStyle 、nWidth 、crColor 的含义与CPen ( int nPenStyle , int nWidth . COLORREF crColor )中的对应参数相同。 返回值:如果函数运行成功,返回非0 值,否则返回0. 例如:创建5 个单位粗、红色、虚线的画笔还有如下方法 CPen Pen2; Pen2.CreatePen ( PS_DASH , 5 , RGB ( 255 , 0 , 0 ) ) ; 二、将画笔载入DC 在创建了画笔之后,必须使用CDC的成员函数Selectobject把画笔载入DC,以替换DC中原来配置的默认画笔,然后才能使用该画笔绘制线条。Selectobject函数的原型为: CPen*Selectobject(CPen*pPen); 其参数为欲载入画笔的指针,返回值为原来画笔的指针。因为在DC内只能存在一个画笔对象,所以在程序中应定义一个保存原画笔的指针变量,来保留Selectobject函数的返回值,以便在新画笔使用后,恢复原画笔。即在程序中应有如下代码: CPen newPen(PS_SOLID,width,color); //创建新画笔 CPen*oldPen=pDC->Selectobject(&newPen); //载入新画笔并把旧画笔存入指针变量oldPen 一旦将画笔或画刷等选进设备描述表对象,它会保留在设备描述表对象内一直到再次选入新的画笔或画刷为止。为了不影响其他模块的绘图工作,一般在一个函数内改变了设备描述符表的画笔或画刷等属性时,应在该函数退出前再恢复设备描述符表原来的属性,方法是调用SelectObjeet ( )函数并以旧的画笔或画刷作为其参数。 在使用新画笔绘制线条之后,如果要恢复原画笔,则需使用如下代码: pDC->Selectobject(oldPen); 以把保存在指针oldPen中的旧画笔重新载人DC。 例7-3一个绘制多种画笔样式及多种颜色线条的应用程序。 (1)用MFC AppWizard创建一个名称为ex7-3的单文档应用程序框架。 (2)在视图类中的OnDraw函数中添加语句,添加后的代码为: void CEx7_3View::OnDraw(CDC *pDC) { CEx7_3Doc *pDoc=GetDocument(); ASSERT_VALID(pDoc); //TODO : add draw code for native data here int style[]={PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT,PS_DASHDOTDOT }; int red=0,green=0,blue=0; int row=20; for(int s=0;s<5;s++) { int color=RGB(red,green,blue); CPen newPen(style[s],1,color); CPen *oldPen=pDC->SelectObject(&newPen); pDC->MoveTo(20,row); pDC->LineTo(300,row); pDC->SelectObject(oldPen); red+=32; green+=16; blue+=8; row+=20; } } 程序运行结果见图7-3。 图7-3 例7-3 程序的运行结果 表7-4所列画笔的样式中,除了实线之外,其他的样式只在画笔的参数nWidth =1时有效。 7.4.3画刷 画笔用来画图,而画刷用来对所画封闭图形进行填充,默认情况下用背景颜色进行填充。如果需要使用新颜色或者图案对一个封闭的图形内部进行填充,就要创建并载入画刷。可以创建并选择一个空画刷,使Windows 不对图形进行填充,这样画图时就不会覆盖原来屏幕上的内容。 一、 创建画刷 创建画刷有两种方法:一步构造法和二步构造法。 1、 一步构造法 在使用画刷之前,要使用CBrush类的构造函数来完成画刷对象的创建及初始化,构造函数的原型为: CBrush(COLORREF color); 和 CBrush(int style,COLORREF color); 其中,参数style用来决定画刷的样式,color用来决定画刷的颜色.参数style可选值见表7-5。 表7-5 style的可选值 填充样式 说明 HS_BDIAGONAL 45度从左上到右下 HS_DIAGCROSS 45度叉线 HS_FDIAGONAL 45度从左下到右上 HS_CROSS 垂直相交的阴影线 HS_HORIZONTAL 水平阴影线 HS_VERTICAL 垂直阴影线 例如CBrush Brush1(RGB( 0 , 255 , 0) ) ; //创建绿色画刷 CBrush Brush2(HS_CROSS,RGB( 0 , 255 , 0) ) ; //创建绿色十字交叉线画刷 2、二步构造法 首先用CBrush 类的无参构造函数构造CBrush 类的对象,然后调用CBrush 类的CreateSolidBrush()或CreateHatchBrush ( )等函数初始化画刷对象。 (1)用CreateSolidBrush()函数可以创建实心的画刷(内部用单一颜色均匀填充),格式如下: bool CreateSolidBrush (COLORREF crColor ) ; 参数crColor 指定画刷的颜色。 返回值:如果函数运行成功,返回非0 值,否则返回0。 例如: CBrush Brush3 Brush3. CreateSolidBrush (RGB (0,255, 0)); //创建绿色画刷 (2) 用CreateHatchBrush()函数可以创建影线的画刷(内部用斜线或网线填充),格式如下: bool CreateHatchBrush(int style, COLORREF color); 参数style用来决定画刷的样式,color用来决定画刷的颜色。 返回值:如果函数运行成功,返回非0 值,否则返回0。 例如: CBrush Brush4 Brush4. CreateHatchBrush(HS_CROSS,RGB(0 , 255 , 0)) ; //创建绿色十字交叉线画刷 二、将画刷载入DC 与使用画笔一样,在创建了画刷之后,如果要使用该画刷,则应该使用CDC类的成员函数SelectObject(),把画刷选入设备描述环境。函数原型如下: CBrush*SelectObject(CBrush*pBrush); 还要定义一个画刷指针,用来保存该函数返回的旧画刷指针。 例7-4画刷的应用。 (1)用MFC AppWizard创建一个名称为ex7-4的单文档应用程序框架。 (2)在视图类的函数OnDraw中输人如下代码: void CEx7_4View::OnDraw(CDC *pDC) { CEx7_4Doc *pDoc=GetDocument(); ASSERT_VALID(pDoc); //TODO : add draw code for native data here int red=0,green=0,blue=0; int row=10; int style[]={HS_BDIAGONAL,HS_CROSS,HS_DIAGCROSS,HS_FDIAGONAL, HS_HORIZONTAL,HS_VERTICAL}; for(int s=0;s<6;s++) { int clr=RGB(red,green,blue); CBrush newBrush(style[s], clr); CBrush *oldBrush=pDC->SelectObject(&newBrush); pDC->Rectangle(20,row,200,row+10); pDC->SelectObject(oldBrush); row+=20; } } 程序运行结果见图7-4。 图7-4 例7-4程序的运行结果 7 . 5绘图模式 在Windows中,绘图的最终效果可以通过设定不同的绘图模式来修饰。绘图模式决定新绘制的图形与屏幕上原有内容的逐位交互关系。例如以黑色画笔画线,当所画线经过屏幕上的一块黑色区域时,线将不可见,通过设置绘图模式可以让线在经过黑色区域时自动变为白色,从而达到可见的目的。 设置绘图模式的CDC成员函数为: SetROP2(int nDrawMode); 其中,参数nDrawMode为欲设置的绘图模式,返回值为原来的绘图模式。绘图模式的选项范围从完全忽略屏幕显示内容用画笔简单地画图到完全忽略画笔仅保留屏幕内容。Windows 有16 种不同的绘图模式,如表7-6 所示。 表7-6 Windows的绘图模式 代码 绘图模式 R2_BLACK 无论画笔颜色如何,只用黑色绘图 R2_WHITE 无论画笔颜色如何,只用白色绘图 R2_NOP 无论画笔颜色如何,只用无色绘图 R2_NOT 用与背景色相反的颜色绘图 R2_COPYPEN 用画笔颜色绘图 R2_NOTCOPYPEN 用与画笔色相反的颜色绘图 R2_MERGEPENNOT 像素颜色=((NOT 屏幕颜色) OR 笔颜色) R2_MASKPENNOT 像素颜色=((NOT 屏幕颜色) AND 笔颜色) R2_MERGENOTPEN 像素颜色=((NOT 笔颜色) OR 屏幕颜色) R2_MASKNOTPEN 像素颜色=((NOT 笔颜色) AND 屏幕颜色) R2_MERGEPEN 像素颜色=(笔颜色 OR 屏幕颜色) R2_NOTMERGEPEN 像素颜色=NOT(笔颜色 OR 屏幕颜色) R2_MASKPEN 像素颜色=(笔颜色 AND 屏幕颜色) R2_NOTMASKPEN 像素颜色=NOT(笔颜色 AND 屏幕颜色) R2_XORPEN 像素颜色=(笔颜色 XOR 屏幕颜色) R2_NOTXORPEN 像素颜色=NOT(笔颜色 XOR 屏幕颜色) 如果用R2_NOT绘图模式,它简单地以逐位方式改变屏幕上的显示。用此画笔绘图时,白色将变为黑色,黑色将变为白色。如果用它再一次绘制同一条直线,它将擦除直线,并恢复原来屏幕颜色。 获得绘图模式的CDC成员函数为: int GetROP2 ( ) const ; 此函数返回当前的绘图模式。 7.6常用CDC类绘图函数 CDC类封装了大量的绘图函数,下面介绍常用的函数。 1、画点函数SetPixel SetPixel( )函数用于画点,它有两个重载版本,函数原形如下: COLORREF SetPixel ( int X , //参数X为点的横坐标 int Y, //参数Y为点的纵坐标 COLORREF crColor //参数crColor为点的颜色 ) COLORREF Setpixel ( POINT point , //参数point为点位置的POINT 类型变量 COLORREF crColor ) SetPixel( )函数的返回值是实际所画点的颜色,若操作失败(如指定的点位置在客户区之外),则返回l 。 2、设置画笔当前位置的函数MoveToEx 设置画笔当前位置的函数MoveToEx的原型如下: BOOL MoveToEx ( int X, //参数X,Y为新位置的逻辑坐标 int Y, LPPOINT lpPoint //lpPoint为存放原画笔位置的POINT结构地址 ) CDC 类的另一个函数MoveTo( )也用于移动当前点的位置,原型如下: CPoint MoveTo ( int X, //参数X、Y 指定当前点的新位置 int Y ) CPoint MoveTo ( POINT point //参数point 指定当前点的新位置 ) 3、从当前位置向指定坐标点画直线的函数LineToEx 从当前位置向指定坐标点画直线的函数LineToEx的原型如下: BOOL LineToEx (int X, //参数X、Y 指定直线的终点位置 int Y ) BOOL LineToEx ( POINT point //参数point 指定直线的终点位置 ) 4、从当前位置开始,依次用线段连接lpPoints中指定各点的函数Ployline 该函数的原型如下: BOOL Ployline ( LPPOINT lpPoints, //lpPoints为指向包含个点坐标的POINT结构数组的指针 int nCount //nCount为POINT数组中点的个数 ) 5、绘制椭圆弧线的函数Arc 绘制椭圆弧线的函数Arc的原型如下: BOOL Arc ( int X1, int Y1, //指定边框矩形左上角的逻辑坐标 int X2, int Y2, //指定边框矩形右下角的逻辑坐标 int X3, int Y3, //椭圆弧起始径线的确定点坐标 int X4, int Y4 //椭圆弧终止径线的确定点坐标 ) Arc函数所画的椭圆弧线由给定边框矩形所形成的椭圆定义,这个矩形由左上角逻辑坐标(X1,Y1)和右下角逻辑坐标(X2,Y2)确定。该弧的起点是(X3,Y3)和矩形中心的连线与椭圆的交点,终点为(X4,Y4)和矩形中心的连线与椭圆的交点。而且该弧是从起点向终点逆时针画出,如图7-5所示。 图7-5 Arc函数所画曲线示意图 6、使用当前画笔绘制一个饼图,并使用当前画刷进行填充的函数Pie 该函数原型如下: BOOL Pie ( int X1, int Y1, //指定边框矩形左上角的逻辑坐标 int X2, int Y2, //指定边框矩形右下角的逻辑坐标 int X3, int Y3, //椭圆弧起始径线的确定点坐标 int X4, int Y4 //椭圆弧终止径线的确定点坐标 ) Pie函数所画饼图为椭圆弧线和两条径线所围的区域,如图7-6所示。 图7-6 Pie函数所画填充区域示意图 7、使用当前画笔绘制一个矩形,并使用当前画刷进行填充的函数Rectangle 该函数的原型如下: BOOL Rectangle ( int X1, int Y1, //(X1,Y1)为边界矩形左上角的逻辑坐标 int X2, int Y2 //(X2,Y2)为边界矩形右下角的逻辑坐标 ) 8、使用当前画笔绘制一个圆角矩形,并使用当前画刷进行填充的函数RoundRect 该函数的原型如下: BOOL RoundRect ( HDC hdc, int X1, int Y1, //(X1,Y1)为边界矩形左上角的逻辑坐标 int X2, int Y2, //(X2,Y2)为边界矩形右下角的逻辑坐标 int nWidth, // nWidth为圆角的宽度 int nHeight // nHeight为圆角的高度 ) 9、使用当前画笔绘制一个椭圆,并使用当前画刷进行填充的函数Ellipse 该函数的原型如下: BOOL Ellipse ( int X1, int Y1, //(X1,Y1为边界矩形左上角的逻辑坐标 int X2, int Y2 //(X2,Y2)为边界矩形右下角的逻辑坐标 ) 10、使用当前画笔绘制一个多边形,并使用当前画刷进行填充的函数Polygon 该函数的原型如下: BOOL Polygon ( LPPOINT lpPoints, //lpPoints为包含个点坐标的POINT数组的地址 int nCount // nCount为多边形点的个数 ) 11、图形填充函数FloodFill 该函数的原型如下: FloodFill ( int x , //参数x 为点的横坐标, int y , //参数y 为点的纵坐标 COLORREF crColor //参数crColor为边界颜色 ) 用CDC 类的FloodFill ( )成员函数可完成对封闭图形的填充。点的坐标必须位于被填充的封闭图形内,边界颜色参数指定Windows 遇到该颜色时就停止填充工作。图形必须是封闭的,否则会由于在某一方向上遇不到指定边界颜色而填充整个窗口。 例如: CDC dc dc.SetROP2 (R2_BLACK ) ; //此句设定用黑色对图形进行填充 dc.FloodFill(point.x, point.y, RGB(0, 0, 0)) ; //对point 指定点所在的封闭图形填充,图形的边线为黑色 7.7绘图过程及应用实例 在MFC环境下绘图时,首先用MFC应用程序向导创建一个的单文档或多文档应用程序框架,然后在视图类中的OnDraw()函数中TODO语句后面添加语句,实现具体的绘图功能,具体步骤如下: (1)设置映像模式 (2)设置窗口、视口的大小 (3)设置画笔 (4)设置画刷 (5)画笔选入设备环境 (6)画刷选入设备环境 (7)设置绘图模式 (8)用绘图函数绘制各种图形 其中的1-7步可以省略,使用默认值绘图。 例7-5 试用MFC屏幕绘图方法绘制图形,要求雪人的位置不随窗口大小的改变而改变,雪人形状如图7-7所示。 图7-7 例7-5画出雪人 实现本例的步骤及代码如下: (1) 新建一个单文档应用程序ex7_5。 (2) 在View类函数OnDraw(CDC* pDC)中添加下列代码: void CEx7_5View::OnDraw(CDC* pDC) { CEx7_5Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here RECT rect; GetClientRect(&rect); //RECT中的元素,left窗口左上角x 坐标;top窗口右上角y坐标一般为(0,0) //right窗口右下角x坐标;bottom窗口右下角y的坐标 pDC->SetWindowOrg(rect.left,rect.top); pDC->SetViewportOrg(rect.left,rect.top); pDC->SetViewportExt(rect.right,rect.bottom); pDC->SetWindowExt(rect.right/2,rect.bottom/2); CPen pen1(PS_SOLID,1,RGB(0,0,0)); CBrush brush1(RGB(255,251,240)); CBrush brush2(RGB(255,0,0)); CBrush brush3(RGB(160,160,164)); CPen*oldpen=pDC->SelectObject(&pen1); pDC->SelectObject(&brush3); pDC->Ellipse(115,250,336,285); //雪人影子 pDC->SelectObject(&brush1); pDC->Ellipse(27,99,233,280); //雪人身子 pDC->Ellipse(81,22,177,118); pDC->SelectObject(&brush2); pDC->Ellipse(113,54,129,70); //雪人眼睛 pDC->Ellipse(145,54,161,70); CPoint points[3]; //雪人鼻子 points[0].x = 139; points[0].y = 79; points[1].x = 171; points[1].y = 75; points[2].x = 139; points[2].y = 94; pDC->Polygon(points,3); } 例7-6试用MFC屏幕绘图方法绘制图形,图形形状如图7-8所示。要求如下: (1) 图形居中放置; (2) 图形随窗口的变大而变大,变小而变小并且位置居中不变; 图7-8 例7-6绘制图形 实现本例要求的步骤及代码: (1)新建一个名为ex7_6的单文档应用程序 (2)在Cex7_6View.h文件中public下添加成员变量代码如下: //添加成员变量 int nMode;//定义映射模式 int i; int j; int m;//记录循环次数 CPoint points[5];//定义坐标点 int radius;//圆半径 char *charout; int Px;//左上角X坐标 int Py;//左上角Y坐标 int Pm;//右下角X坐标 int Pn;//右下角Y坐标 TEXTMETRIC tm; CRect rect; CPen pen; CBrush brush; //成员变量完 (3)在CEx7_6View.cpp文件中找到CEx7_6View.:: CEx7_6View ()构造函数为该函数添加代码如下: Cex7_6View.:: Cex7_6View () { nMode=MM_ANISOTROPIC;//定义映射模式 i=0; j=0; m=0; //记录循环次数 radius=0; //圆半径 charout=NULL; //存储输出的字符串 Px=0; //左上角X坐标 Py=0; //左上角Y坐标 Pm=0; //右下角X坐标 Pn=0; //右下角Y坐标 } (4)在CEx7_6View.cpp文件中找到void CEx7_6View::OnDraw(CDC* pDC)在函数中添加如下代码: void CEx7_6View::OnDraw(CDC *pDC) { CEx7_6Doc *pDoc=GetDocument(); ASSERT_VALID(pDoc); //TODO : add draw code for native data here pDC->SetMapMode(nMode); GetClientRect(&rect); //RECT中的元素,left窗口左上角x坐标; //top窗口右上角y坐标一般为(0,0) //right窗口右下角x坐标;bottom窗口右下角y的坐标 SetWindowOrgEx(*pDC,rect.left-rect.right/2,rect.top-rect.bottom/2,NULL); SetWindowExtEx(*pDC,rect.right,rect.bottom,NULL); SetViewportOrgEx(*pDC,rect.left,rect.top,NULL); SetViewportExtEx(*pDC,rect.right,rect.bottom,NULL); radius=(int)((rect.bottom)/2); pen.CreatePen(PS_SOLID,1,RGB(255,0,0)); pDC->SelectObject(pen); brush.CreateSolidBrush(RGB(255,0,0)); pDC->SelectObject(brush); charout="五角星"; pDC->GetTextMetrics(&tm); pDC->TextOut(40,40,charout,lstrlen(charout)); /********************** 坐标赋值*********************************/ for(m=0;m<3;m++) { for(i=0,j=0;i<5;i++,j+=2) { if(j>5) { j-=5; } points[i].x=(long)(radius*cos(j*72.0/180*PI)); points[i].y=(long)(radius*sin(j*72.0/180*PI)); } radius=(int)(radius*sin(0.085*PI)/sin(126.0/180*PI)); pDC->Polygon(points,5); } /***********删除画笔画刷********************/ pen.DeleteObject(); brush.DeleteObject(); } (5)在Cex7_6View.cpp文件的开始部分添加如下代码: #include "math.h" #define PI 3.1415926 (6)在CEx7_6View::~CEx7_6View()中添加如下代码: CEx7_6View::~CEx7_6View() { nMode=MM_ANISOTROPIC;//定义映射模式 i=0; j=0; m=0; //记录循环次数 radius=0; //圆半径 charout=NULL; //存储输出的字符串 Px=0; //左上角X坐标 Py=0; //左上角Y坐标 Pm=0; //右下角X坐标 Pn=0; //右下角Y坐标 } 7 . 7 文本输出 在Windows中,文本是作为图形来加以显示的,因此用户必须与设备描述环境打交道,并且还要处理与字体有关的一些问题。 1、文本的显示 Windows 中常用CDC类的TextOut ( )成员函数来显示一个字符串。Textout()函数有两个重载版本 ,原型如下: virtual BOOL Textout BOOL Textout ( intx , int y ,LPCTSTR lpszString,int nCount); BOOL TextOut(int x,int y,const CString &str); 在第一个版本的Textout 中,参数x , y 指定显示字符串的起始坐标,lpszString 为指向待显示字符串的指针,nCount 为字符个数。在第二个版本的TextOut 中,参数x , y 指定显示字符串的起始坐标,而待显示的字符串由str 给出。这两个版本的TextOut ,显示成功均返回非0 值,显示不成功返回0。 2、设置文本颜色 在默认的情况下,文本的颜色为黑色,文本的背景颜色为白色。如果显示文本时要指定前景颜色,可用CDC 类的SetTextColo()函数,原型如下: virtual COLORREF SetTextColor ( COLORREF crColor ) ; 此函数设置输出文本的颜色为crColor 参数指定的值,函数的返回值为设置前的文本颜色值。与其相对应的,CDC类还有一个可以获得当前文本颜色的函数,原型如下: COLORREF GetTextColor() const; 如果显示文本时要指定背景颜色,可用CDC 类的SetTBkColor函数,原型如下: virtual COLORREF SetBkColor ( COLORREF crColor); 此函数设置输出文本的背景颜色为crColor 参数指定的值,函数的返回值为设置前的文本背景颜色值。与这个函数相对应的,CDC类还有一个获得当前背景颜色的成员函数,原型如下: COLORREF GetBkColor() const; 3、设置文本字符的间距 在需要改变文本的字符之间的间隔(间距)时,可以使用CDC类的成员函数SetTextCharacterExtra,原型如下: int SetTextCharacterExtra(int nCharExtra); 参数nCharExtra用来设置文本字符的额外间隔,该参数是以像素为单位的。函数的返回值为字符的原间距。与设置字符间距函数相对应的,CDC类还有一个获取当前字符间距的函数,原型如下: int GetTextCharacterExtra() const; 4、设置文本的对齐方式 在实际应用中,常常需要以不同的对齐方式显示文本,例如要左对齐文本或右对齐文本,当然也有时需要把文本显示在窗口中间。为了实现文本的不同对齐要求,MFC在CDC类中提供了一个专门用来实现文本对齐方式的函数,原型如下: UINT SetTextAlign(UINT nFlags); 参数nFlags 用于指定对齐方式,可为表7-7 中的值。 表7-7文本的对齐方式 符号常数 含义 对齐方向 TA_CENTER 字符串居中对齐 影响文本在X方向上的对齐方式 TA_LEFT 字符串左对齐(默认设置) TA_RIGHT 字符串右对齐 TA_BASELINE 将点同所选字符的基线对齐 影响文本在Y方向上的对齐方式 TA_BOTTOM 字符串下端对齐 TA_TOP 字符串上端对齐(默认设置) TA_NOUPDATECP 每次调用文本输出函数后当前位置不更新(默认设置) 决定了显示字符后当前位置是否更新 TA_UPDATECP 每次调用文本输出函数后更新当前位置的X坐标值 一次可以指定两组以上的值,各个值间用按位与符号“|”连起来即可。 例7-7文本颜色、字符间距及对齐方式的应用。 (1)用MFC AppWizard创建一个名称为ex7_7的单文档应用程序框架. (2)在视图类的OnDraw函数中输人如下代码: void CEx7_7View::OnDraw(CDC *pDC) { CEx7_7Doc *pDoc=GetDocument(); ASSERT_VALID(pDoc); //TODO : add draw code for native data here pDC->SetTextAlign(TA_LEFT);//左对齐 pDC->SetTextColor(RGB(255,0,0)); pDC->SetBkColor(RGB(0,0,255)); pDC->TextOut(220,20,"AAAAAAAAA"); pDC->TextOut(220,40,"HHHHH"); pDC->TextOut(220,60,"SSSSSSSSSSSSSSSS"); pDC->SetTextAlign(TA_CENTER); //中间对齐 pDC->SetTextCharacterExtra(4); //字符间距为4 pDC->TextOut(220,80,"AAAAAAAAA"); pDC->TextOut(220,100,"HHHHH"); pDC->TextOut(220,120,"SSSSSSSSSSSSSSSS"); pDC->SetTextAlign(TA_RIGHT); //右对齐 pDC->SetTextColor(RGB(0,255,0)); pDC->SetBkColor(RGB(255,0,255)); pDC->TextOut(220,140,"AAAAAAAAA"); pDC->TextOut(220,160,"HHHHH"); pDC->TextOut(220,180,"SSSSSSSSSSSSSSSS"); } 程序运行结果见图7-9。 图7-9例7-7程序的运行结果 5、在Windows 里删除文本 通过一个填充矩形来覆盖文本可以清除文本。可以用GetBKColor( )函数获得背景颜色,并建立此种颜色的画笔和实线型画刷,然后用Rectangle ( )函数画矩形删除此文本。

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 5 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档