第 7 章屏幕绘图及文本显示

60
1 第 7 第第第第第第第第第第

Upload: alika

Post on 23-Jan-2016

74 views

Category:

Documents


0 download

DESCRIPTION

第 7 章屏幕绘图及文本显示. 7.1GDI 与设备描述表 7.1.1GDI 的基本概念 Windows 图形设备接口 GDI ( Graphical Device Interface )是为与设备无关的图形设计的。所谓 设备的无关性 ,就是操作系统屏蔽了硬件设备的差异,因而设备无关性能使用户编程时无需考虑特殊的硬件设置。 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 7 章屏幕绘图及文本显示

1

第 7 章屏幕绘图及文本显示

Page 2: 第 7 章屏幕绘图及文本显示

2

7.1GDI 与设备描述表7.1.1GDI 的基本概念 Windows 图形设备接口 GDI ( Graphical Device Interface )是为与设备无关的图形设计的。所谓设备的无关性,就是操作系统屏蔽了硬件设备的差异,因而设备无关性能使用户编程时无需考虑特殊的硬件设置。 Windows 把与绘图工作相关的操作都制作成了函数, GDI 提供了用户可以调用的一套用于绘图的函数集。无论基础硬件如何,同一函数都能够生成相同结果。例如,调用 GDI 函数中的Ellipse 函数可以绘制椭圆,调用 TextOut 函数可以绘制文本,调用 Rectangle 函数可以绘制矩形等。 除了这些绘图函数之外, GDI 还有一套用于绘图的工具(对象),比如画刷、画笔等。 文本被看作是图形,这种处理方式虽然在创建文本输出时增加了复杂度,但也增强了灵活性。可以让原本在文本世界非常困难的工作变得非常轻松。

Page 3: 第 7 章屏幕绘图及文本显示

3

7.1.2 设备描述环境 为了简化应用这些性质不同的设备的访问,实现与设备无关的绘图操作, Windows 提供了一种叫做设备描述表的机制,也称为设备环境 DC(Device Context) ,它是 Windows 应用程序与设备驱动程序和输出设备(如打印机、显示器等)之间的接口,用来作为应用程序与控制输出设备的低层之间的通道。 设备描述表是一种可以在其上绘图的“逻辑画布”,它接收应用程序的绘图命令,再将其翻译为控制设备驱动程序的低层指令。程序员可以在这个虚拟的图形显示对象上进行绘图,而把这个图形最终转换为实际物理设备上图形的工作则交给系统去完成。 设备环境 DC ( Device Context )是由 GDI 保存的一个数据结构,设备环境包含了输出设备的绘图特征,不同设备有不同的设备环境,在输出设备上输出的先决条件是获得该设备的设备环境。例如,为了在屏幕上显示绘图, Window 程序必须有该显示器的一个 DC 。为了在打印机输出,还需要另一个专门为打印机创建的 DC 。

Page 4: 第 7 章屏幕绘图及文本显示

4

Windows 中的设备描述表(硬件多态)分为以下4 种类型。

(1) 显示器型:支持显示器上的绘图操作。

(2) 打印机型:支持打印机和绘图仪上的绘图操作。

(3) 内存型:支持位图上的绘制操作。

(4) 信息型:支持设备数据的访问。

打印机

绘图仪

显示器

程序员使用

GDI 函数在设备描述环境中

绘图设备描述环

Page 5: 第 7 章屏幕绘图及文本显示

5

为了方便, Windows 系统初始化了一套 DC 的属性和对象,表 7-1 为显示器 DC 的属性及默认值,获得了该设备的 DC 后,程序设计人员就可以在这个默认的环境下开始绘图工作了。当然,如果程序员对预置的属性和对象不满意的话,也可以按自己的要求对它们进行设置。例如,默认的 DC 中预置了一支黑色画笔,所以这时用 GDI 的绘图函数绘制的任何线条都是黑色的。如果想使用其它颜色绘制线条的话,程序员可以用其它颜色的画笔来替换这支黑色的画笔。 DC 在任何时候总是必须存在着一套完整的绘图工具。这意味着,不能从 DC 中删除一个工具,只能用一个工具替换另一个工具。绘图过程可描述为使用 GDI 对象(逻辑画笔或画刷等)在设备描述表(逻辑画布)上绘制的过程

Page 6: 第 7 章屏幕绘图及文本显示

6

属性 默认值背景色 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)

Page 7: 第 7 章屏幕绘图及文本显示

7

7.2CDC类 MFC 的 CDC类对设备描述表和 GDI 函数进行了全面的封装,使这两者的使用更加方便。 CDC 类是一个通用的类,可以从它派生出特定类型的 DC子类。

1.CDC 类的成员函数由于 DC 与屏幕绘图及文本显示操作密切相关, CDC 类的成员函数主要包括以下几类: (1) 初始化函数,比如为指定的设备创建设备描述符表等。(2) 设备描述符表函数,比如保存或恢复 DC 的状态等。(3) 绘图及其相关函数,比如设置绘图前景颜色、背景颜色、绘图工具选择、图形绘制等。(4) 文本与字体函数,比如文本输出、字体信息的取得等。(5)坐标与映射函数,比如设置映射方式、各种坐标的转换等。

Page 8: 第 7 章屏幕绘图及文本显示

8

2.几种派生的 CDC类

类名 说明CClientDC 在相应除WM_PAINT消息之外的消息处理函数中,提供窗口

客户区的设备描述环境。

CMetaFileDC 代表Windows图元文件的设备描述环境。在创建与设备无关的并且可以回放的图像时使用这个类型的 DC。

CPaintDC 在 OnDraw()函数中使用的窗口用户区的设备描述环境。在MFC中用 OnDraw()来处理WM_PAINT消息。

CWindowDC 提供在整个窗口内(不只是用户区)绘图的设备描述环境。

Page 9: 第 7 章屏幕绘图及文本显示

9

CPaintDC 是所有 CDC 类中最常用的一个类,它代表了应用程序窗口的客户区,它只能使用在 CView 类的 OnDraw 函数中。 OnDraw 函数的声明为:Void OnDraw(CDC*pDC);对应用程序窗口的客户区进行绘图的所有代码都必须写 ( 被调用 ) 在这个函数中。应用程序窗口在每次创建及需要刷新时就会产生 WM_PAINT 消息,如用户区移动或显示,用户窗口大小改变,程序通过滚动条滚动窗口,窗口被另一个窗口覆盖的恢复,还有下拉式菜单关闭等,这些情况下就会发送 WM_PAINT 消息。系统接收到这个消息就会自动调用OnDraw 函数。这个函数的参数 pDC 就是指向 CPaintDC 对象的指针,在 OnDraw 的函数体中,就可以通过这个指针来使用 DC 类的成员函数进行绘图操作了。

Page 10: 第 7 章屏幕绘图及文本显示

10

【例 7-1】在用户区显示字符串“ Hello” 。( 1 )用 MFCAppwizard 创建一个名称为 ex7_1 的单文档应用程序框架。( 2 )在视图类中的 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 herepDC->TextOut(50,50,"HELLO");// 输出字符串的语句

}对于 WM_PAINT 消息的响应,框架代码已经做了大量的工作,已经自动处理了 DC 的申请与释放的问题,用户所要做的只是在 OnDraw() 函数内完成绘图工作即可。下面的几节中,主要是在 CPaintDC 中绘图。

Page 11: 第 7 章屏幕绘图及文本显示

11

7.3映射模式 映射模式是设备描述符表 DC 的一个重要属性,它影响到GDI 绘图及文本的显示效果。7.3.1 设备坐标 图形或文字要在物理设备(如显示器、打印机等)上输出,就必须使用该物理设备的坐标系统,称为设备坐标。设备坐标以设备的最小分辨单位——像素为基本单位,以左上角为坐标原点, X 轴向右延伸, Y 轴向下延伸 最常用的设备坐标就是屏幕的设备坐标,这里面又包含几种具体的设备坐标系。若以整个屏幕为范围,就是“屏幕坐标系统”,像WM_MOVE消息这样不依赖于窗口的消息,必须以整个屏幕为参照物,使用的是屏幕坐标。若以整个窗口为基准,将标题栏、菜单、滚动条、窗口边框等均计算在内,这种坐标称为“窗口坐标系统”,一般情况下窗口坐标较少使用。若以窗口的用户区为范围,点( 0 , 0 )位于用户区的左上角,这种坐标称为用户区坐标,这是最常用的一种设备坐标。

Page 12: 第 7 章屏幕绘图及文本显示

12

7.3.2 逻辑坐标 如果直接使用设备坐标绘图,由于屏幕和打印机的分辨率不同,同样是 100 个像素长的一条直线,在两种设备上的实际输出长度将不相同。假设程序员想画一条在两种设备上都是 10cm长的直线,将不得不针对屏幕和打印机的分辨率分别计算它们各需要包含多少个设备像素。为了解决这个问题,在 GDI 绘图中使用了逻辑坐标这一概念。逻辑坐标使用的是逻辑单位,逻辑单位与设备无关,比如逻辑单位是 0.lmm ,则一条 100 个逻辑单位长的直线,不论是显示在屏幕上,还是输出到打印机上,都是 10cm 长。虽然最终显示或打印时仍然要使用像素点(设备坐标),但一个逻辑单位应该映射为物理设备上的多少个像素点,是由 Windows 自动处理的。本章后面几小节介绍的 GDI 绘图函数使用的都是逻辑坐标。

Page 13: 第 7 章屏幕绘图及文本显示

13

坐标变换(曲面 to平面) 屏幕的高 (y) 和宽 (h) ,地理坐标区域的范围

(maxLon , minLon , maxLat , minLat)

比例因子:算出每像素所代表的经度和纬度 scaleX = ((maxLon-minLon)*3600)/h --X轴每像素代表的经度秒数; scaleY = ((maxLat-minLat)*3600)/y ---Y轴每像素代表的纬度秒数;

经纬度转屏幕坐标公式 X = (lon - minLon)*3600/scaleX; Y = (maxLat - lat)*3600/scaleY;

屏幕坐标转经纬度坐标公式 lon = X * scaleX/3600 + minLon; lat = maxLat - y* scaleY/3600;

为了保证精度,地理坐标的度 *3600 换算成秒,所有的取值用 double 来计算,最后的结果再转换成 int 。

Page 14: 第 7 章屏幕绘图及文本显示

14

7.3.3映射模式映像模式定义了将逻辑单位转化为设备的度量单位的

方法以及设备的 X 方向和 Y 方向,程序员可在一个统一的逻辑坐标系中操作而不必考虑输出设备的坐标系情况。映射模式对应用程序是很重要的。 Windows 中定义了 8 种映射模式

Page 15: 第 7 章屏幕绘图及文本显示

15

映射模式 将一个逻辑单位映射为

X轴 Y轴

MM_TEXT(默认) 1像素 向右 向下

MM_LOMETRIC 0.1毫米 向右 向上

MM_HIMETRIC 0.01毫米 向右 向上

MM_LOENGLISH 0.01英寸 向右 向上

MM_HIENGLISH 0.001英寸 向右 向上

MM_TWIPS ( 1/20) 1/1440英寸 向右 向上

MM_ISOTROPIC (各向同性) 任意 (X=Y) 可选 可选

MM_ANISOTROPIC (各向异性) 任意 (X!=Y) 可选 可选

Page 16: 第 7 章屏幕绘图及文本显示

16

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 ; 此函数的返回值是当前的映射模式。

Page 17: 第 7 章屏幕绘图及文本显示

17

【例 7-2】将“ Hello World” 显示在离客户区左边和上边各 l 英寸的地方。

( 1 )用 MFCAppwizard 创建一个名称为 ex7_2 的单文档应用程序框架。

( 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” ) ; // 输出字符串的语句}

Page 18: 第 7 章屏幕绘图及文本显示

18

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 时才有意义。

Page 19: 第 7 章屏幕绘图及文本显示

19

7.4 绘图工具的使用Windows 提供了一些工具用于绘图,这些工具有:画笔( Pe

n )、画刷( Brush )、位图 ( Bitmap )、字体( Font )、调色板( Palette )、区域( Region )等,这些都称为 GDI 对象。

7.4.1GDI 绘图工具介绍1. 画笔画笔是一种用来画线或有形边框的工具,可以指定它的颜色及宽

度,也可以指定线型(实线、点线、虚线等)。2. 画刷画刷(或称为刷子)定义了一种位图形式的像素模板,利用它可

以对区域内部填以颜色。3.位图位图定义了每个显示像素的颜色,可以用来表示图像,以及图标、光标、刷子等的形状。

Page 20: 第 7 章屏幕绘图及文本显示

20

4.字体字体是一种具有某种风格和尺寸的所有字符的完整集合,它常常

被当作资源存在磁盘中。字体用来控制文字的显示。5. 调色板调色板是一种颜色映射表,利用它可以使应用程序最大可能地使

用输出设备的颜色输出能力,而无须严重于扰其它程序使用的颜色。

6.区域区域由位于一个窗口内的椭圆或多边形组合而成,可以用来进行填充、剪裁以及鼠标选中测试等。

MFC 中用 CPen类封装了 Windows 的画笔、用 CBrush 类封装了 Windows 的画刷、用 CBitmap即类封装了 Windows 的位图、用 CFont 类封装了 Windows 的字体、用 CPalette 类封装了 Windows 的调色板、用 CRgn 类封装了 Windows 的区域。

Page 21: 第 7 章屏幕绘图及文本显示

21

CPen 类的构造函数为:CPen ( int nPenstyle , int nWidth , COLORREF

crColor ) 样式 颜色宽度

CPen Pen1 ( PS_DASH , 5 , RGB ( 255 , 0 , 0 ) ) ;// 栈中stack

/ / 创建 5 个单位粗红色虚线的画笔

7.4.2 画笔1. 创建画笔一步构造法 :

利用 CPen 类的带参构造函数来完成画笔对象的创建及初始化。 CPen 类的带参构造函数有两个重载版本,下面介绍最常用的一个。

Page 22: 第 7 章屏幕绘图及文本显示

22

样式 说明PS_SOLID 画实线PS_DASH 画虚线PS_DOT 画点线PS_DASHDOT 画点划线PS_DASHDOTDOT 画双点划线PS_NULL 不可见的画笔PS_INSIDEFRAME 在一个图形内画边划线的画笔

参数 nPenstyle 指定画笔的风格,表 7-4 中列出了最常用的取值。

Page 23: 第 7 章屏幕绘图及文本显示

23

参数 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 Pen1(PS_DASH , 1 , RGB ( 255 , 0 , 0 )); / / 创建 1 个单位

粗、红色、虚线的画笔

Page 24: 第 7 章屏幕绘图及文本显示

24

二步构造法:首先用 CPen 类的无参构造函数构造 CPen 类的对象,然后调用 CPen 类的CreatePen( ) 函数初始化画笔对象。

BOOL CreatePen ( int nPenstyle , int nWidth , COLORREF crColor )

样式 颜色宽度

CPen Pen2; Pen2.CreatePen ( PS_DASH , 5 , RGB ( 255 , 0 , 0 ) ) ; // 创建 5 个单位粗红色虚线的画笔 , // 栈中stack

Page 25: 第 7 章屏幕绘图及文本显示

25

动态构造法:首先 new 出 CPen 类的有参或无参构造函数构造 CPen 类的对象及初始化画笔对象。然后,使用画笔对象,最后 delete删除对象。

CPen *npen = new CPen(style[s],1,color);//3,堆中

heapCPen *oldPen=pDC->SelectObject(npen);//3pDC->MoveTo(20,row);pDC->LineTo(300,row);pDC->SelectObject(oldPen);red+=32;green+=16;blue+=8;row+=20;delete npen;//3,释放堆内存

Page 26: 第 7 章屏幕绘图及文本显示

26

2. 将画笔载入 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 。

Page 27: 第 7 章屏幕绘图及文本显示

27

【例 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;

Page 28: 第 7 章屏幕绘图及文本显示

28

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;

}}

Page 29: 第 7 章屏幕绘图及文本显示

29

7.4.3 画刷画笔用来画图,而画刷用来对所画封闭图形进行填充,默认情况

下用背景颜色进行填充。如果需要使用新颜色或者图案对一个封闭的图形内部进行填充,就要创建并载入画刷。可以创建并选择一个空画刷,使 Windows 不对图形进行填充,这样画图时就不会覆盖原来屏幕上的内容。

1. 创建画刷创建画刷有两种方法:一步构造法和二步构造法。一步构造法在使用画刷之前,要使用 CBrush类的构造函数来完成画刷对象

的创建及初始化,构造函数的原型为:CBrush(COLORREF color);和 CBrush(int style,COLORREF color);其中,参数 style 用来决定画刷的样式, color 用来决定画刷的颜

色.参数 style 可选值见表 7-5 。

Page 30: 第 7 章屏幕绘图及文本显示

30

CBrush Brush1 ( RGB( 0 , 255 , 0) ) ; // 创建绿色画刷CBrush Brush2 ( HS_CROSS,RGB( 0 , 255 , 0) ) ; // 创建绿色十字交叉线画刷

填充样式 说明

HS_BDIAGONAL 45度从左上到右下

HS_DIAGCROSS 45度叉线

HS_FDIAGONAL 45度从左下到右上

HS_CROSS 垂直相交的阴影线

HS_HORIZONTAL 水平阴影线

HS_VERTICAL 垂直阴影线

Page 31: 第 7 章屏幕绘图及文本显示

31

二步构造法首先用 CBrush 类的无参构造函数构造 CBrush 类的对象,

然后调用 CBrush 类的 CreateSolidBrush ()或CreateHatchBrush ( )等函数初始化画刷对象。

(1) 用 CreateSolidBrush ()函数可以创建实心的画刷(内部用单一颜色均匀填充),格式如下:

bool CreateSolidBrush (COLORREF crColor ) ; 参数 crColor 指定画刷的颜色。返回值:如果函数运行成功,返回非 0 值,否则返回 0 。例如:CBrush Brush3Brush3. CreateSolidBrush (RGB (0,255, 0)); // 创建绿色画刷(2) 用 CreateHatchBrush() 函数可以创建影线的画刷(内部

用斜线或网线填充),格式如下:bool CreateHatchBrush(int style, COLORREF color);参数 style 用来决定画刷的样式, color 用来决定画刷的颜色。返回值:如果函数运行成功,返回非 0 值,否则返回 0 。

Page 32: 第 7 章屏幕绘图及文本显示

32

例如:CBrush Brush4Brush4. CreateHatchBrush ( HS_CROSS,RGB(0 , 255 , 0)) ;

// 创建绿色十字交叉线画刷2. 将画刷载入 DC与使用画笔一样,在创建了画刷之后,如果要使用该画刷,

则应该使用 CDC类的成员函数 SelectObject() ,把画刷选入设备描述环境。函数原型如下:

CBrush*SelectObject(CBrush*pBrush);还要定义一个画刷指针,用来保存该函数返回的旧画刷指针。

3. 动态构造法(?)

Page 33: 第 7 章屏幕绘图及文本显示

33

【例 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};

Page 34: 第 7 章屏幕绘图及文本显示

34

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;

}}

Page 35: 第 7 章屏幕绘图及文本显示

35

7.5 绘图模式在 Windows 中,绘图的最终效果可以通过设定不同的绘图模

式来修饰。绘图模式决定新绘制的图形与屏幕上原有内容的逐位交互关系。例如以黑色画笔画线,当所画线经过屏幕上的一块黑色区域时,线将不可见,通过设置绘图模式可以让线在经过黑色区域时自动变为白色,从而达到可见的目的。

设置绘图模式的 CDC 成员函数为:SetROP2(int nDrawMode);

其中,参数 nDrawMode 为欲设置的绘图模式,返回值为原来的绘图模式。绘图模式的选项范围从完全忽略屏幕显示内容用画笔简单地画图到完全忽略画笔仅保留屏幕内容。 Windows 有 16 种不同的绘图模式

Page 36: 第 7 章屏幕绘图及文本显示

36

代码 绘图模式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 屏幕颜色 )

Page 37: 第 7 章屏幕绘图及文本显示

37

如果用 R2_NOT 绘图模式,它简单地以逐位方式改变屏幕上的显示。用此画笔绘图时,白色将变为黑色,黑色将变为白色。如果用它再一次绘制同一条直线,它将擦除直线,并恢复原来屏幕颜色。

获得绘图模式的 CDC 成员函数为:int GetROP2 ( ) const ; // 不允许修改

此函数返回当前的绘图模式。

Page 38: 第 7 章屏幕绘图及文本显示

38

7.6 常用 CDC类绘图函数CDC类封装了大量的绘图函数,下面介绍常用的函数。

1.画点函数 SetPixelSetPixel( ) 函数用于画点,它有两个重载版本,函数原形如下:COLORREF SetPixel (

int X , //参数 X 为点的横坐标int Y, //参数 Y 为点的纵坐标COLORREF crColor //参数 crColor 为点的颜色

)COLORREF Setpixel(

POINT point , //参数 point 为点位置的 POINT 类型变量

COLORREF crColor ) SetPixel( ) 函数的返回值是实际所画点的颜色,若操作失败(如指定的点位置在客户区之外),则返回 l 。

Page 39: 第 7 章屏幕绘图及文本显示

39

2.设置画笔当前位置的函数 MoveTo 的原型如下:CPoint MoveTo( int X, //参数 X 、 Y 指定当前点的新位置

int Y) CPoint MoveTo(

POINT point //参数 point 指定当前点的新位置)

3.从当前位置向指定坐标点画直线的函数 LineTo BOOL LineTo ( int X, //参数 X 、 Y 指定直线的终点位置

int Y) BOOL LineTo (

POINT point //参数 point 指定直线的终点位置)

Page 40: 第 7 章屏幕绘图及文本显示

40

4.从当前位置开始,依次用线段连接 lpPoints 中指定各点的函数 PloylineBOOL Polyline ( LPPOINT lpPoints, // 指向包含各点坐标的 POINT 结构数组的指针 int nCount // nCount 为 POINT 数组中点的个数)

例如POINT points[6]={{100,212},{70,227},{70,250},{130,250},{130,227},{100,212}};

Polyline(points,6); // 画一个五边形

Page 41: 第 7 章屏幕绘图及文本显示

41

5. 绘制椭圆弧线的函数 Arc ,BOOL Arc

(int X1,intY1, //边框矩形左上角的逻辑坐标int X2,int Y2, //边框矩形右下角的逻辑坐标int X3,int Y3, // 椭圆弧起始点坐标int X4,int Y4 // 椭圆弧终止点坐标)

(x1,y1)

(x2,y2)

(x3,y3)

(x4,y4)所画曲线

Page 42: 第 7 章屏幕绘图及文本显示

42

6. 绘制饼图,并用当前画刷进行填充BOOL Pie

(int X1,intY1, //边框矩形左上角的逻辑坐标int X2,int Y2, //边框矩形右下角的逻辑坐标int X3,int Y3, // 椭圆弧起始经线的确定点坐标int X4,int Y4 // 椭圆弧终止经线的确定点坐标)

(x1,y1)

(x2,y2)

(x3,y3)

(x4,y4)所填区域

Page 43: 第 7 章屏幕绘图及文本显示

43

7. 绘制矩形,并用当前画刷进行填充BOOL Rectangle(int X1,int Y1,int X2,int Y2)

(X1 , Y1 )和(X2 , Y2 )分别为矩形的左上角和右下角的逻辑坐标

8. 绘制圆角矩形,并用当前画刷填充BOOL RoundRect (int X1,int Y1,int X2,int Y2, int nHeight, int nWidth)

圆角的高度和宽度

9. 绘制椭圆,并用当前画刷填充 BOOL Ellipse(intX1,intY1,intX2,intY2)

10.绘制多边形,并用当前画刷填充BOOL Polygon(LPPOINT lpPoints,int nCount)

包含各点坐标的POINT 数组的地址 多边形点的个数

Page 44: 第 7 章屏幕绘图及文本显示

44

11. 图形填充函数 FloodFill该函数的原型如下:FloodFill(

int x , //参数 x 为点的横坐标,int y , //参数 y 为点的纵坐标COLORREF crColor //参数 crColor 为边界颜色

)

用 CDC 类的 FloodFill ( )成员函数可完成对封闭图形的填充。点的坐标必须位于被填充的封闭图形内,边界颜色参数指定Windows 遇到该颜色时就停止填充工作。图形必须是封闭的,否则会由于在某一方向上遇不到指定边界颜色而填充整个窗口。

例如:CDC dcdc.SetROP2 (R2_BLACK ) ; //此句设定用黑色对图形进行填充dc.FloodFill(point.x, point.y, RGB(0, 0, 0)) ; // 对 point 指定点所在

的封闭图形填充,图形的边线为黑色

Page 45: 第 7 章屏幕绘图及文本显示

45

7.7 绘图过程及应用实例在 MFC 环境下绘图时,首先用 MFC 应用程序向导创

建一个的单文档或多文档应用程序框架,然后在视图类中的 OnDraw() 函数中 TODO语句后面添加语句,实现具体的绘图功能,具体步骤如下:

( 1 )设置映像模式:逻辑单位转化为设备坐标的单位和 xy轴向( 2 )设置窗口、视口大小: MM_ANISOTROPIC 和 MM_ISOTROPIC

( 3 )设置画笔: 3

( 4 )设置画刷: 3

( 5 )画笔选入设备环境: pDC-> SelectObject

( 6 )画刷选入设备环境 pDC-> SelectObject

( 7 )设置绘图模式:新旧图形关系( 8 )用绘图函数绘制各种图形其中的 1-7步可以省略,使用默认值绘图。

Page 46: 第 7 章屏幕绘图及文本显示

46

【例 7-5】试用 MFC 屏幕绘图方法绘制图形,要求雪人的位置不随窗口大小的改变而改变,雪人形状如图 7-7 所示。

Page 47: 第 7 章屏幕绘图及文本显示

47

新建一个单文档应用程序 ex7_5 。在 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);

Page 48: 第 7 章屏幕绘图及文本显示

48

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);

Page 49: 第 7 章屏幕绘图及文本显示

49

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);}

Page 50: 第 7 章屏幕绘图及文本显示

50

class CSnowMan类设计 struct SnowMan{ CHead head; CEye leye; CEye reye; CNose nose; CBody body; CArm larm; CArm rarm; CLeg lleg; CLeg rleg; };

class CSnowMan{ public: CSnowMan(){} CSnowMan(CShowManDoc* pDoc,

CDC* pDC){ m_pDoc=pDoc; m_pDC=pDC; } void makeSnowman(int , RECT, int); private: //CString m_id; vector<SnowMan> snowman; CShowManDoc* m_pDoc; CDC* m_pDC; };

Page 51: 第 7 章屏幕绘图及文本显示

51

【例 7-6 】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));CString si,sx,sy,sxy;si.Format("%d",i);sx.Format("%d",points[i].x);sy.Format("%d",points[i].y);sxy=si+" ("+sx+" , "+sy+")";pDC->TextOut(points[i].x,points[i].y,sxy);}radius=(int)(radius*sin(0.085*PI)/sin(126.0/180*PI));pDC->Polygon(points,5);

Page 52: 第 7 章屏幕绘图及文本显示

52

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 。

Page 53: 第 7 章屏幕绘图及文本显示

53

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;

Page 54: 第 7 章屏幕绘图及文本显示

54

3. 设置文本字符的间距在需要改变文本的字符之间的间隔(间距)时,可以使用 CDC类的成员函数

SetTextCharacterExtra ,原型如下:int SetTextCharacterExtra(int nCharExtra);参数 nCharExtra 用来设置文本字符的额外间隔,该参数是以像素为单位的。函数的返回值为字符的原间距。与设置字符间距函数相对应的, CDC类还有一个获取当前字符间距的函数,原型如下:

int GetTextCharacterExtra() const;

4. 设置文本的对齐方式在实际应用中,常常需要以不同的对齐方式显示文本,例如要左

对齐文本或右对齐文本,当然也有时需要把文本显示在窗口中间。为了实现文本的不同对齐要求, MFC 在 CDC类中提供了一个专门用来实现文本对齐方式的函数,原型如下:

UINT SetTextAlign(UINT nFlags);

Page 55: 第 7 章屏幕绘图及文本显示

55

符号常数 含义 对齐方向TA_CENTER 字符串居中对齐 影响文本在 X

方向上的对齐方式TA_LEFT 字符串左对齐(默认设置)

TA_RIGHT 字符串右对齐

TA_BASELINE 将点同所选字符的基线对齐 影响文本在 Y方向上的对齐方式TA_BOTTOM 字符串下端对齐

TA_TOP 字符串上端对齐(默认设置)

TA_NOUPDATECP 每次调用文本输出函数后当前位置不更新(默认设置)

决定了显示字符后当前位置是否更新

TA_UPDATECP 每次调用文本输出函数后更新当前位置的 X坐标值

表 7-7 文本的对齐方式

Page 56: 第 7 章屏幕绘图及文本显示

56

【例 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");

Page 57: 第 7 章屏幕绘图及文本显示

57

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");

}

Page 58: 第 7 章屏幕绘图及文本显示

58

5. 在 Windows 里删除文本通过一个填充矩形来覆盖文本可以清除文本。可以用

GetBKColor( ) 函数获得背景颜色,并建立此种颜色的画笔和实线型画刷,然后用 Rectangle ( ) 函数画矩形删除此文本。

隐藏!

Page 59: 第 7 章屏幕绘图及文本显示

59

实验P132:7-9,7-10,7-11第四个综合设计:中国地图。点( Pie )

状城市用圆符号;线( Polyline )状河流用线符号;面( Polygon 、 FloodFill )数据状省市用多边形符号。各层考虑合理的分级,分色。所需数据自己解决并参考 OGC SFS 进行简单的地图数据结构设计(数组或向量存储)。

Page 60: 第 7 章屏幕绘图及文本显示

60

1. GIS 数据采集(同学数据): 姓 名 生日 邮箱 经度 纬度 籍贯…

2. 类设计: CFriends

3. 坐标变换: 经纬度到屏幕坐标变换1. 屏幕到经纬度坐标变换

4. 地图绘显: 点、线、面图层(中国城市,道路,省区) CCity 、 CRoad 、 CProvince

“多媒体同学地图系统”,分为同学基本信息管理、图形表达、多媒体和网络聊天等功能模块(插件)。