1、1第 7 章屏幕绘图及文本显示屏幕是最基本的输出设备,屏幕绘图及文本显示是应用程序最常用的功能,本章讲述VisualC +中屏幕绘图及文本显示的工作原理及其基本编程方法。首先介绍 GDI 与设备描述表,然后介绍 CDC 类、映射方式等概念,最后介绍基本的绘图函数及文本显示函数的用法。7.1 GDI 与设备描述表Windows 操作系统是一个图形界面的操作系统,为了方便地在屏幕上和打印机上绘制或输出图形与文本,Windows 系统中为用户提供了设备描述表和 GDI 函数来实现应用程序与物理设备间的接口。7.1.1 GDI 的基本概念Windows 图形设备接口 GDI(Graphical Dev
2、ice Interface)是为与设备无关的图形设计的。所谓设备的无关性,就是操作系统屏蔽了硬件设备的差异,因而设备无关性能使用户编程时无需考虑特殊的硬件设置。Windows 把与绘图工作相关的操作都制作成了函数, GDI 提供了用户可以调用的一套用于绘图的函数集。无论基础硬件如何,同一函数都能够生成相同结果。例如,调用GDI 函数中的 Ellipse 函数可以绘制椭圆,调用 TextOut 函数可以绘制文本,调用 Rectangle函数可以绘制矩形等。除了这些绘图函数之外,GDI 还有一套用于绘图的工具(对象) ,比如画刷、画笔等。GDI 绘图工具的使用在 7.4 小节中介绍。文本被看作是图
3、形,这种处理方式虽然在创建文本输出时增加了复杂度,但也增强了灵活性。可以让原本在文本世界非常困难的工作变得非常轻松。7.1.2 设备描述环境Windows 下,有多种输出设备,如各种显示器、打印机、绘图仪等。由于用来显示图形的实际物理设备的多样性,因此要求程序设计人员具有对所有图形显示设备的编程能力是不现实的。为了简化应用这些性质不同的设备的访问,实现与设备无关的绘图操作,Windows 提供了一种叫做设备描述表的机制,也称为设备环境 DC(Device Context),它是Windows 应用程序与设备驱动程序和输出设备(如打印机、显示器等)之间的接口,用来作为应用程序与控制输出设备的低层
4、之间的通道。设备描述表是一种可以在其上绘图的“逻辑画布” ,它接收应用程序的绘图命令,再将其翻译为控制设备驱动程序的低层指令。程序员可以在这个虚拟的图形显示对象上进行绘图,而把这个图形最终转换为实际物理设备上图形的工作则交给系统去完成。这样,通过设备描述符表机制,程序可以独立于“真实”的硬件。设备环境 DC(Device Context)是由 GDI 保存的一个数据结构,设备环境包含了输出设备的绘图特征,不同设备有不同的设备环境,在输出设备上输出的先决条件是获得该设备的设备环境。例如,为了在屏幕上显示绘图,Window 程序必须有该显示器的一个 DC。为了在打印机输出,还需要另一个专门为打印机
5、创建的 DC。Windows 中的设备描述表分为以下 4 种类型。显示器型:支持显示器上的绘图操作。2打印机型:支持打印机和绘图仪上的绘图操作。内存型:支持位图上的绘制操作。信息型:支持设备数据的访问。为了方便,Windows 系统初始化了一套 DC 的属性和对象,表 7-1 为显示器 DC 的属性及默认值,获得了该设备的 DC 后,程序设计人员就可以在这个默认的环境下开始绘图工作了。当然,如果程序员对预置的属性和对象不满意的话,也可以按自己的要求对它们进行设置。例如,默认的 DC 中预置了一支黑色画笔,所以这时用 GDI 的绘图函数绘制的任何线条都是黑色的。如果想使用其他颜色绘制线条的话,程
6、序员可以用其他颜色的画笔来替换这支黑色的画笔。DC 在任何时候总是必须存在着一套完整的绘图工具。这意味着,不能从 DC 中删除一个工具,只能用一个工具替换另一个工具。绘图过程可描述为使用GDI 对象(逻辑画笔或画刷等)在设备描述表(逻辑画布)上绘制的过程。表 7-1 显示器 DC 的属性及默认值属性 默认值背景色 WHITE背景模式 OPAQUE位图 NONE画刷 WHITE_BRUSH画刷起始位置 (0,0)剪截域 DISPLAY SURFACE颜色调色板 DEFAULT_PALETTE绘图方式 R2_COPYPEN字体 SYSTEM_FONT字符间距 0映射方式 MM_TEXT画笔 BLA
7、CE_PEN多边形填充方式 ALTERNATE缩放模式 BLACKONWHITE文本颜色 BLACK试图范围 (1,1)视图原点 (0,0)窗口范围 (1,1)窗口原点 (0,0)7 . 2CDC 类MFC 的 CDC 类对设备描述表和 GDI 函数进行了全面的封装,使这两者的使用更加方便。CDC 类是一个通用的类,可以从它派生出特定类型的 DC 子类。1、CDC 类的成员函数由于 DC 与屏幕绘图及文本显示操作密切相关,CDC 类的成员函数主要包括以下几类: 初始化函数,比如为指定的设备创建设备描述符表等。3设备描述符表函数,比如保存或恢复 DC 的状态等。绘图及其相关函数,比如设置绘图前景
8、颜色、背景颜色、绘图工具选择、图形绘制等。文本与字体函数,比如文本输出、字体信息的取得等。坐标与映射函数,比如设置映射方式、各种坐标的转换等。具体函数用法在 7.6 小节中介绍。2、几种派生的 CDC 类几种派生的 CDC 类如表 7-2 所示表 7-2 几种派生的 CDC 类CPaintDC 是所有 CDC 类中最常用的一个类,它代表了应用程序窗口的客户区,它只能使用在 CView 类的 OnDraw 函数中。OnDraw 函数的声明为:OnDraw(CDC*pDC);对应用程序窗口的客户区进行绘图的所有代码都必须写在这个函数中。应用程序窗口在每次创建及需要刷新时就会产生 WM_PAINT
9、消息,如用户区移动或显示,用户窗口大小改变,程序通过滚动条滚动窗口,窗口被另一个窗口覆盖的恢复,还有下拉式菜单关闭等,这些情况下就会发送 WM_PAINT 消息。系统接收到这个消息就会自动调用 OnDraw函数。这个函数的参数 pDC 就是指向 CPaintDC 对象的指针,在 OnDraw 的函数体中,就可以通过这个指针来使用 DC 类的成员函数进行绘图操作了。例 7_1 在用户区显示字符串“Hello World ”。用 MFCAppwizard 创建一个名称为 ex7_1 的单文档应用程序框架。在视图类中的 OnDraw 函数中添加语句:pDC-Textout(50,50, “HELLO
10、 ”),即视图类的代码为:void CEx7_1View:OnDraw(CDC *pDC)CEx7_1Doc *pDoc=GetDocument();ASSERT_VALID(pDoc);/TODO : add draw code for native data herepDC-TextOut(50,50,“HELLO“);/输出字符串的语句程序运行结果如图 7-1 所示。对于 WM_PAINT 消息的响应,框架代码已经做了大量的工作,已经自动处理了 DC 的申类名 说明CClientDC 在相应除 WM_PAINT 消息之外的消息处理函数中,提供窗口客户区的设备描述环境。CMetaFileD
11、C 代表 Windows 图元文件的设备描述环境。在创建与设备无关的并且可以回放的图像时使用这个类型的 DC。CPaintDC 在 OnDraw()函数中使用的窗口用户区的设备描述环境。在 MFC 中用OnDraw()来处理 WM_PAINT 消息。CWindowDC 提供在整个窗口内(不只是用户区)绘图的设备描述环境。4请与释放的问题,用户所要做的只是在 OnDraw()函数内完成绘图工作即可。下面的几节中,主要是在 CPaintDC 中绘图。图 7-1 例 7-1 程序的运行结果图73 映射模式映射模式是设备描述符表 DC 的一个重要属性,它影响到 GDI 绘图及文本的显示效果。7 .3.
12、 1 设备坐标图形或文字要在物理设备(如显示器、打印机等)上输出,就必须使用该物理设备的坐标系统,称为设备坐标。设备坐标以设备的最小分辨单位像素为基本单位,以左上角为坐标原点,X 轴向右延伸,Y 轴向下延伸,如图 7-2 所示。图 7-2 设备坐标系最常用的设备坐标就是屏幕的设备坐标,这里面又包含几种具体的设备坐标系。若以整个屏幕为范围,就是“屏幕坐标系统” ,像 WM_MOVE 消息这样不依赖于窗口的消息,必须以整个屏幕为参照物,使用的是屏幕坐标。若以整个窗口为基准,将标题栏、菜单、滚动条、窗口边框等均计算在内,这种坐标称为“窗口坐标系统” ,一般情况下窗口坐标较少使用。若以窗口的用户区为范
13、围,点(0 , 0 )位于用户区的左上角,这种坐标称为用户区坐标,这是最常用的一种设备坐标。函数 ClientToScreen( )和 ScreenToClient ( )可以将5用户区坐标转换为屏幕坐标,或者将屏幕坐标转换为用户区坐标。7 . 3. 2 逻辑坐标如果直接使用设备坐标绘图,由于屏幕和打印机的分辨率不同,同样是 100 个像素长的一条直线,在两种设备上的实际输出长度将不相同。假设程序员想画一条在两种设备上都是 10cm 长的直线,将不得不针对屏幕和打印机的分辨率分别计算它们各需要包含多少个设备像素。为了解决这个问题,在 GDI 绘图中使用了逻辑坐标这一概念。逻辑坐标使用的是逻辑单
14、位,逻辑单位与设备无关,比如逻辑单位是 0.lmm ,则一条 100 个逻辑单位长的直线,不论是显示在屏幕上,还是输出到打印机上,都是 10cm 长。虽然最终显示或打印时仍然要使用像素点(设备坐标) ,但一个逻辑单位应该映射为物理设备上的多少个像素点,是由 Windows 自动处理的。本章后面几小节介绍的 GDI 绘图函数使用的都是逻辑坐标。7 . 3. 3 映射模式映像模式定义了将逻辑单位转化为设备的度量单位的方法以及设备的 X 方向和 Y 方向,程序员可在一个统一的逻辑坐标系中操作而不必考虑输出设备的坐标系情况。映射模式对应用程序是很重要的。Windows 中定义了 8 种映射模式,如表
15、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 是最简单的一种映射模式,也是默认的映射模式,它使得逻辑坐标完全等价于设备坐标。其他几种
16、映射模式下,逻辑坐标的原点也位于窗口的左上角,但对于 Y 轴是向下增长的。MM_ANISOTROPIC 和 MM_ISOTROPIC 这两种映射模式通过将图形从程序员定义的逻辑坐标窗口映射到物理设备的视口以实现坐标转换。窗口是对应逻辑坐标系上程序员设定的区域,视口是对应实际输出设备上程序员设定的区域。这两种映射模式的区别是MM_ANISOTROPIC 按照窗口和视口的坐标比例进行映射,而 MM_ISOTROPIC 将窗口中的对称图形映射到视口时仍为对称图形。在 MM_ISOTROPIC 映射模式下,圆总是圆的,但是在 MM_ANISOTROPIC 映射模式下,圆可以被拉扁成椭圆形状。1、映射模
17、式的设置要改变 DC 的映射模式,可以使用 CDC 类的 SetMapMode( )函数,函数原型形为:virtual int SetMapMode ( int nMapMode); 参数 nMapMode 是新设置的映射模式,函数的返回值是 DC 先前的映射模式。6若要取得 DC 当前的映射模式,可以使用 CDC 类的函数 GetMapMode( ),函数原型形为:int GetMapMode ( ) const ; 此函数的返回值是当前的映射模式。例 7-2 将“Hello World ”显示在离客户区左边和上边各 l 英寸的地方。用 MFCAppwizard 创建一个名称为 ex7_2
18、的单文档应用程序框架。在视图类中的 OnDraw 函数中添加语句,添加后的代码为:void CEx7_2View:OnDraw(CDC *pDC)CEx7_2Doc *pDoc=GetDocument();ASSERT_VALID(pDoc);/TODO : add draw code for native data herepDC-SetMapMode(MM_LOENGLISH) ; pDC-Textout (100 ,-100 , “Hello World” ) ; /输出字符串的语句2、设置窗口和视口的大小窗口区域的定义由 SetWindowExtEx 函数完成,其函数原型为:BOOL
19、SetWindowExtEx ( int nHeight /以逻辑单位表示的窗口区域高度int nWidth, /以逻辑单位表示的窗口区域宽度LPSIZE lpSize, /函数调用前窗口区域尺寸的 SIZE 结构地址);视口区域的定义由 SetViewportExtEx 函数完成,函数原型为:BOOL SetViewportExtEx( int nHeight /以逻辑单位表示的视口区域高度int nWidth, /以逻辑单位表示的视口区域宽度LPSIZE lpSize /函数调用前视口区域尺寸的 SIZE 结构地址);设置窗口和视口的大小只有在映射模式为 MM_ANISOTROPIC 和
20、MM_ISOTROPIC 时才有意义。7 . 4 绘图工具的使用Windows 提供了一些工具用于绘图,这些工具有:画笔(Pen) 、画刷(Brush) 、位图( Bitmap) 、字体( Font) 、调色板(Palette) 、区域(Region )等,这些都称为 GDI 对象。7 . 4. 1 GDI 绘图工具介绍( l )画笔:画笔是一种用来画线或有形边框的工具,可以指定它的颜色及宽度,也可以指定线型(实线、点线、虚线等) 。( 2 )画刷:画刷(或称为刷子)定义了一种位图形式的像素模板,利用它可以对区域内部填以颜色。( 3 )位图:位图定义了每个显示像素的颜色,可以用来表示图像,以及
21、图标、光标、刷子等的形状。7( 4 )字体:字体是一种具有某种风格和尺寸的所有字符的完整集合,它常常被当作资源存在磁盘中。字体用来控制文字的显示。( 5 )调色板:调色板是一种颜色映射表,利用它可以使应用程序最大可能地使用输出设备的颜色输出能力,而无须严重于扰其他程序使用的颜色。( 6 )区域:区域由位于一个窗口内的椭圆或多边形组合而成,可以用来进行填充、剪裁以及鼠标选中测试等。MFC 中用 CPen 类封装了 Windows 的画笔、用 CBrush 类封装了 Windows 的画刷、用 CBitmap 即类封装了 Windows 的位图、用 CFont 类封装了 Windows 的字体、用
22、CPalette 类封装了 Windows 的调色板、用 CRgn 类封装了 Windows 的区域。7 . 4 . 2 画笔画笔是绘图的基本工具,在 MFC 中画笔是 CPen 类的对象,它可以用来完成各种画线条的任务。DC 在初始化时,就自动配备了一个黑色的默认画笔。如果程序设计人员对这个默认的画笔不满意,要改变线的颜色、粗细、线型等属性需要创建新的画笔对象,并将其载入 DC 中以取代默认的画笔即可。一、创建画笔创建画笔有两种方法:一步构造法和二步构造法。1、一步构造法利用 CPen 类的带参构造函数来完成画笔对象的创建及初始化。CPen 类的带参构造函数有两个重载版本,下面介绍最常用的一
23、个。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 C
24、OLORREF RGB( BYTE bRed, /红色(0255)BYTE bGreen, /绿色(0255 )BYTE bBlue /蓝色(0255);例如:8RGB ( 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 类的无参构造函数构造 CPe
25、n 类的对象,然后调用 CPen 类的CreatePen( )或 CreatePenIndirect( )函数初始化画笔对象。下面介绍 CreatePen( )函数,此函数有两个重载版本,最常用的版本如下:BOOL CreatePen ( int nPenstyle , int nWidth , COLORREF crColor ) ;参数:nPenStyle 、nWidth 、crColor 的含义与 CPen ( int nPenStyle , int nWidth . COLORREF crColor )中的对应参数相同。返回值:如果函数运行成功,返回非 0 值,否则返回 0. 例如:创
26、建 5 个单位粗、红色、虚线的画笔还有如下方法CPen Pen2; Pen2.CreatePen ( PS_DASH , 5 , RGB ( 255 , 0 , 0 ) ) ; 二、将画笔载入 DC在创建了画笔之后,必须使用 CDC 的成员函数 Selectobject 把画笔载入 DC,以替换DC 中原来配置的默认画笔,然后才能使用该画笔绘制线条。Selectobject 函数的原型为:CPen*Selectobject(CPen*pPen);其参数为欲载入画笔的指针,返回值为原来画笔的指针。因为在 DC 内只能存在一个画笔对象,所以在程序中应定义一个保存原画笔的指针变量,来保留 Selec
27、tobject 函数的返回值,以便在新画笔使用后,恢复原画笔。即在程序中应有如下代码:CPen newPen(PS_SOLID,width,color); /创建新画笔 CPen*oldPen=pDC-Selectobject( /载入新画笔并把旧画笔存入指针变量oldPen一旦将画笔或画刷等选进设备描述表对象,它会保留在设备描述表对象内一直到再次选入新的画笔或画刷为止。为了不影响其他模块的绘图工作,一般在一个函数内改变了设备描述符表的画笔或画刷等属性时,应在该函数退出前再恢复设备描述符表原来的属性,方法是调用 SelectObjeet ( )函数并以旧的画笔或画刷作为其参数。在使用新画笔绘制
28、线条之后,如果要恢复原画笔,则需使用如下代码: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);9/TODO : add draw code for native dat
29、a hereint 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;sSelectObject(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
30、=1 时有效。7.4.3 画刷画笔用来画图,而画刷用来对所画封闭图形进行填充,默认情况下用背景颜色进行填充。如果需要使用新颜色或者图案对一个封闭的图形内部进行填充,就要创建并载入画刷。可以创建并选择一个空画刷,使 Windows 不对图形进行填充,这样画图时就不会覆盖原来屏幕上的内容。一、创建画刷创建画刷有两种方法:一步构造法和二步构造法。101、 一步构造法在使用画刷之前,要使用 CBrush 类的构造函数来完成画刷对象的创建及初始化,构造函数的原型为:CBrush(COLORREF color);和CBrush(int style,COLORREF color);其中,参数 style 用
31、来决定画刷的样式,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、二步构造法首先用 CB
32、rush 类的无参构造函数构造 CBrush 类的对象,然后调用 CBrush 类的CreateSolidBrush()或 CreateHatchBrush ( )等函数初始化画刷对象。 (1)用 CreateSolidBrush()函数可以创建实心的画刷(内部用单一颜色均匀填充) ,格式如下:bool CreateSolidBrush (COLORREF crColor ) ; 参数 crColor 指定画刷的颜色。返回值:如果函数运行成功,返回非 0 值,否则返回 0。例如:CBrush Brush3Brush3. CreateSolidBrush (RGB (0,255, 0); /创建
33、绿色画刷(2) 用 CreateHatchBrush()函数可以创建影线的画刷(内部用斜线或网线填充) ,格式如下:bool CreateHatchBrush(int style, COLORREF color);参数 style 用来决定画刷的样式,color 用来决定画刷的颜色。返回值:如果函数运行成功,返回非 0 值,否则返回 0。例如:CBrush Brush4Brush4. CreateHatchBrush(HS_CROSS,RGB(0 , 255 , 0) ; / 创建绿色十字交叉线画刷二、将画刷载入 DC与使用画笔一样,在创建了画刷之后,如果要使用该画刷,则应该使用 CDC 类的
34、成员11函数 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
35、 data hereint 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;sSelectObject(pDC-Rectangle(20,row,200,row+10);pDC-SelectObject(oldBrush);row+=20;程序运行结果见图 7-4。图 7-4 例 7-4 程序的运行结果127 . 5 绘图模式在 Windows 中,绘图的最终效果可以通过设定不同的绘图模式
36、来修饰。绘图模式决定新绘制的图形与屏幕上原有内容的逐位交互关系。例如以黑色画笔画线,当所画线经过屏幕上的一块黑色区域时,线将不可见,通过设置绘图模式可以让线在经过黑色区域时自动变为白色,从而达到可见的目的。设置绘图模式的 CDC 成员函数为:SetROP2(int nDrawMode);其中,参数 nDrawMode 为欲设置的绘图模式,返回值为原来的绘图模式。绘图模式的选项范围从完全忽略屏幕显示内容用画笔简单地画图到完全忽略画笔仅保留屏幕内容。Windows 有 16 种不同的绘图模式,如表 7-6 所示。表 7-6 Windows 的绘图模式代码 绘图模式R2_BLACK 无论画笔颜色如何
37、,只用黑色绘图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
38、_NOTMERGEPEN 像素颜色=NOT(笔颜色 OR 屏幕颜色)R2_MASKPEN 像素颜色=(笔颜色 AND 屏幕颜色)R2_NOTMASKPEN 像素颜色=NOT(笔颜色 AND 屏幕颜色)R2_XORPEN 像素颜色=(笔颜色 XOR 屏幕颜色)R2_NOTXORPEN 像素颜色=NOT(笔颜色 XOR 屏幕颜色)如果用 R2_NOT 绘图模式,它简单地以逐位方式改变屏幕上的显示。用此画笔绘图时,白色将变为黑色,黑色将变为白色。如果用它再一次绘制同一条直线,它将擦除直线,并恢复原来屏幕颜色。获得绘图模式的 CDC 成员函数为:int GetROP2 ( ) const ; 此函数返
39、回当前的绘图模式。7.6 常用 CDC 类绘图函数CDC 类封装了大量的绘图函数,下面介绍常用的函数。1、画点函数 SetPixelSetPixel( )函数用于画点,它有两个重载版本,函数原形如下:COLORREF SetPixel 13( int X , /参数 X 为点的横坐标int Y, /参数 Y 为点的纵坐标COLORREF crColor /参数 crColor 为点的颜色)COLORREF Setpixel( POINT point , /参数 point 为点位置的 POINT 类型变量COLORREF crColor) SetPixel( )函数的返回值是实际所画点的颜色,
40、若操作失败(如指定的点位置在客户区之外) ,则返回 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、
41、从当前位置向指定坐标点画直线的函数 LineToEx从当前位置向指定坐标点画直线的函数 LineToEx 的原型如下:BOOL LineToEx (int X, /参数 X、Y 指定直线的终点位置int Y) BOOL LineToEx (POINT point /参数 point 指定直线的终点位置)4、从当前位置开始,依次用线段连接 lpPoints 中指定各点的函数 Ployline14该函数的原型如下:BOOL Ployline(LPPOINT lpPoints, /lpPoints 为指向包含个点坐标的 POINT 结构数组的指针int nCount /nCount 为 POINT
42、数组中点的个数) 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)和矩形中心的连线与椭圆的交点。而且该弧是从
43、起点向终点逆时针画出,如图 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 所示。15图 7-6 Pie 函数所画填充区域示意图7、使用当前画笔绘制一个矩形,并使用当前画刷进行填充的
44、函数 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 / nH
45、eight 为圆角的高度)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、图形填充函数 Flood
46、Fill该函数的原型如下:FloodFill16( int x , /参数 x 为点的横坐标,int y , /参数 y 为点的纵坐标COLORREF crColor /参数 crColor 为边界颜色)用 CDC 类的 FloodFill ( )成员函数可完成对封闭图形的填充。点的坐标必须位于被填充的封闭图形内,边界颜色参数指定 Windows 遇到该颜色时就停止填充工作。图形必须是封闭的,否则会由于在某一方向上遇不到指定边界颜色而填充整个窗口。例如:CDC dcdc.SetROP2 (R2_BLACK ) ; /此句设定用黑色对图形进行填充dc.FloodFill(point.x, poi
47、nt.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 屏幕绘图方法绘制图形, 要求雪人的位置
48、不随窗口大 小的改变而改变,雪人形状 如图 7-7 所示。17图 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 hereRECT rect;GetClientRect( /RECT 中的元素, left 窗口左上角 x 坐标;
49、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);CB