1、第5章 图形绘制 在Visual C++6.0中,掌握图形程序设计方法是非常重要的。因为图形在任何一个可视化工程项目中都是不可缺少的。CDC(设备环境)类封装了图形绘制所需要的各种操作。本章我们将通过实际例子和较详细的阐述,来了解和掌握如何使用设备环境类(CDC)及图形设备接口(GDI)进行图形绘制。 5.1 设备环境与设备环境类(CDC) 5.1.1 设备环境 设备环境也称设备上下文(Device Context,简称DC),是计算机物理设备的代表,也是图形设备接口的主要组成部分。 由于Windows是一个与设备无关的操作系统,即Windows不允许直接访问
2、硬件,如果用户想将文本和图形绘制到显示器或其它设备中去,必须通过“设备环境”这个抽象层与硬件进行通信,设备上下文对象的作用就是实现Windows的设备无关性,任何向屏幕上进行输出的功能都要间接地通过它来完成。 设备上下文是Windows的一种数据结构,它包含了有关如显示器或打印机等设备的绘图属性信息。所有绘画都是通过设备上下文对象来实现的,该对象封装了Windows的画线、图形和文本的API函数。设备上下文允许在Windows下独立于设备的绘画。设备上下文不仅能够被用来在屏幕上绘画,它也可以将绘画输出到打印机和图元文件中。 5.1.2 设备环境类 设备环境类CDC直接继承于CObj
3、ect类,该类定义了一类设备对象。CDC对象提供了非常多的成员函数,与设备环境的显示器、打印机等一起工作。例如,如果要在显示器等设备上绘制图形,我们可以用MFC提供的设备环境类CDC类,因为CDC类中包含了绘图所需要的所有成员函数。同时。MFC还提供了以下几个CDC的派生类: 1、CPaintDC类 此类比较特殊,它的构造函数和析构函数都是针对OnPaint进行的。用户一旦获得相关的CDC指针,就可以将它当做任何设备环境(包括屏幕、打印机)指针来使用,CPaintDC类的构造函数会自动调用BeginPaint,而它的析构函数则会自动调用EndPaint。 2、CClientDC和CWin
4、dowDC类 CClientDC只能在窗口的客户区(不包括边框、工具条、标题栏、滚动条、菜单栏以及状态栏)进行绘图,点(0,0)通常指的是客户区的左上角。其构造函数调用GetDC,析构函数调用ReleaseDC函数。 CWindowDC允许在窗口的任意位置中进行绘图,点(0,0)指整个窗口的左上角。 其构造函数调用GetWindowDC,析构函数调用ReleaseDC函数。 3、CMetaFileDC类 封装了在一个Windows图元文件中绘图的方法。图元文件是一系列与设备无关的图片的集合,由于它对图像的保存比像素更精确,因而往往在要求较高的场合下使用,例如:AutoCAD的图像保
5、存等。目前的Windows已使用增强格式(enhanced-format)的32位图元文件来进行操作。设备环境类CDC及其派生类如图5.1.1所示。 CDC CClientDC CPaintDC CWindowDC
6、 图5.1.1 CDC与其子类继承图 5.2 绘图程序 5.2.1 CDC基类 CDC类是其它DC类的基类,CDC类封装了使用设备环境的各种图形设备接口(GDI)函数,它用于定义一个设备环境对象,并提供了在显示器、打印机和窗口的客户区域上画图的方法。 1、在视图类的OnDraw()函数中绘图 在视图类的OnDraw函数中绘图时,直接使用OnDraw()函数中的CDC形参指针pDC,调用它的函数进
7、行绘图: 例5.1 绘制矩形与文本 (1)创建一个单文档应用程序,名为: 显示绘图 (2)在视图类的实现文件“显示绘图 View.cpp”的OnDraw函数中加如下代码: void CMyView::OnDraw(CDC* pDC) { CMyDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); 图5.2.1 绘制矩形和文本 //选择画刷,浅灰色画刷,见表5.2 pDC->SelectStockObject(LTGRAY_BRUSH); CRect rect(10,10,2
8、00,70);//定义一个矩形 pDC->Rectangle(rect);//绘制一个矩形 pDC->TextOut(20,80,"我们会编制图形程序了 !"); //绘制文本 pDC->TextOut(20,100,”努力学好Visual C++ !”); } 3)编译运行,结果如图5.2.1所示。 说明:SelectStockObject( ) 该函数检索预定义的备用笔、刷子、字体或者调色板的句柄。 参数:LTGRAY_BRUSH:亮灰色画笔;BLACK_BRUSH黑色画笔; NULL_BRUSH:空画笔(相当于HOLLOW_BRUSH)
9、 WHITE_BRUSH:白色画笔;BLACK_PEN:黑色钢笔;...... 2、在视图类的一般函数中绘图 例5.2 在鼠标放下函数WM_LBUTTONDOWN函数中绘图 (1)创建一个单文档应用程序,名为:一般函数绘图 (2)利用MFC ClassWizard将鼠标放下WM_LBUTTONDOWN消息映射到视图类CMyView中,并添加代码: void CMyView::OnLButtonDown(UINT nFlags, CPoint point) { //定义一个矩形 CRect rect(0,0,100,100); //GetDC检索整个屏幕的设备上下文环
10、境 CDC *pDC=GetDC(); pDC->Rectangle(rect);//绘制矩形 ReleaseDC(pDC);//释放pDC空间 CView::OnLButtonDown(nFlags, point); } (3)编译运行,鼠标点击窗口,出现 图5.2.2 在OnLButtonDown函数中绘图 图5.2.2所示的矩形。 5.2.2 CPaintDC类 CPaintDC对象代表了一个窗口的绘图画面,主要用来绘图。它可以用来处理来自Windows的WM_PAINT消息。改变窗口大小或移动覆盖在窗上的窗口或对话框时,Windows会发送WM
11、PAINT消息以通知客户区的变动,而WM_PAINT消息的处理是在OnPaint()消息处理函数中进行的。 例5.3 在WM_PAINT消息函数中绘图 (1)创建一个单文档的应用程序,名为:绘图 (2)利用MFC ClassWizard将WM_PAINT消息映射到视图类(View)中,并添加代码: void CMyView::OnPaint() { //CPaintDC dc(this); //调用MoveTo函数,定点到点(10,10) dc.MoveTo(10,10); //调用LineTo函数,画线到点(100,100) dc.LineTo(100,100)
12、 //画线 //调用画椭圆函数Ellipse画椭圆 dc.Ellipse(120,120,160,160); } (3)编译运行,结果见5.2.3所示 画直线图5.2.3 运行结果 5.2.3 CClientDC类 CClientDC对象用来自动处理对描述窗口的客户程序区域的设备环境进行调用和释放。在CClientDC对象创建时自动调用GetDC(),在撤销时将自动调用ReleaseDC()。 例5.4 在客户区画一条直线 (1)创建一个单文档的应用程序,名为:画直线
13、 (2)利用MFC ClassWizard将鼠标放下WM_LBUTTONDOWN消息映射到视图类CMyView中,并添加代码: void CMyView::OnLButtonDown(UINT nFlags, CPoint point) { CClientDC dc(this); CRect rect; //定义一个矩形。 // 取得客户区矩形区域 GetClientRect(&rect); //调用MoveTo,定点到客户区的左上角 dc.MoveTo(rect.left,rect.top); //调用LineTo函数,画线到客户区的右下角 dc.Line
14、To(rect.right,rect.bottom); 图5.2.4 绘制一条直线 } (3)编译运行,鼠标左键点击窗口任一点,便在窗口上画一条直线,如图5.2.4所示。 5.3 图形设备接口(GDI)对象 GDI(Graphic Device Interface)对象与设备环境对象的关系,类似于笔和纸的关系。也就是说,GDI提供了用于在DC上画图的绘图工具。MFC的GDI中包含了各种绘图类并提供各类的绘图函数即定义了若干种对于Windows的绘图工具的
15、对象,该类的继承关系如图5.3.1所示;GDI中包含的各种绘图类有一个共同的抽象基类CGdiObject,具体如表5.1所示: CGdiObject CBitmap CBrush CFont CPalette CPen CRgn 图5.3.1 MFC 的GDI类继承图 1、使用GDI对象 选择GDI对象进行绘图时,一般要遵循下列步骤: (1
16、定义一个GDI对象(如CPen、CBrush对象),然后用相应的函数(如CreatePen、CreateSolidBrush)创建此GDI对象。但要注意;有些GDI派生类的构造函数允许用户提供足够的信息,从而一步即可完成对象的创建任务,这些类有CPen、CBrush。 (2)将构造的GDI对象选入当前设备坏境中,但不要忘记将原来的GDI对象保存起来。 (3)绘图结束后,恢复当前设备环境中原来的GDI对象。 2、库存的GDI对象 除了自定义的GDI对象外,Windows还包含了一些预定义的库存GDI对象。由于它们是Windows系统的一部分,因此用户用不着删除它们。CDC的成员
17、函数SelectStockObject可以把一个库存对象选入当前设备环境中,并返回原先被选中的对象指针,同时使原先被选中的对象从设备环境中分离出来。 函数SelectStockObject可选用的库存GDI对象类型可以是表5.2所示值之一。 表5.1 MFC的GDI类 类 名 说 明 CBitmap “位图”是一种位矩阵,每一个显示像素都对应于其中的一个或多个位,用户可以 利用位图来表示图象,也可以利用它来创建画刷 CBr
18、ush “画刷”定义了一种位图形式的像素,利用它可对区域内部填充颜色或样式 CFont “字体”是一种具有某种风格和尺寸的所有字符的完整集合,它常常 被当做资源存于磁盘中,其中有一些还依赖于某种设备 CPalette “调色板”是一种颜色映射接口,它允许应用程序在不干扰其它应用 程序的前提下,充分利用输出设备的颜色描绘能力 CPen “画笔”是一种用于画线及绘制有形边框的工具,用户可以指定它的 颜色及宽度,并且可以指定它实线、点线或虚线等 CRgn “区域”是由多边形、椭圆或二者组合形成的一种范围,可以利用它 来进行填充、裁剪以及鼠标点中测
19、试等 表5.2 函数SelectStockObject可选用的库存GDI对象类型值 类型值 含 义 BLACK_BRUSH 黑色画刷 DKGRAY_BRUSH 深灰色画刷 GRAY_BRUSH 灰色画刷 HOLLOW_BRUSH
20、 中空画刷 LTGRAY_BRUSH 浅灰色画刷 NULL_BRUSH 空画刷 WHITE_BRUSH 白色画刷 BLACK_PEN 黑色画笔 NULL_PEN 空画笔 WHITE_PEN
21、 白色画笔 DEVICE_DEFAULT_FONT 设备默认字体 SYSTEM_FONT 系统字体 5.3.1 画笔CPen类 CPen类封装了一个Windows GDI画笔,并且提供了用于操作CPen对象的若干方法。CPen类用来决定画线的风格和颜色。在使用画笔之前,首先必须构造画笔对象,有2种方法: (1)构造和初始化对象都在带参数的构造函数中一步完成,如:生成颜色为绿色,宽度为2个像素的实心画笔:CPen newPen(PS_SOL
22、ID,2,RGB(0,255,0)); (2)构造初始化分2步完成:构造由不带参数的构造函数完成,而初始化由初始化函数完成。如:生成颜色为红色,宽度为2个像素的实心画笔: CPen newPen; newPen.CreatePen(PS_SOLID,2,RGB(255,0,0)); 参 数: PS_SOLID: 画笔的风格,见表5.3所示 2: 画笔的宽度(2个像素) RGB(255,0,0):画笔的颜色 表5.3 修饰画笔的风格 风 格 含 义 图例
23、 PS_SOLID 实 线 ————— PS_DASH 虚 线 -------------- PS_DOT 点线 ..…………… PS_DASHDOT 点画线 -.-.-.-.-.-.-.-.-. PS_DASHDOTDOT 双点画线 -..-..-..-..-..-..-
24、 PS_NULL 不可见线 PS_INSIDEFRAME 内框线 ___________ (3)CreatePenIndirect函数也是用于创建画笔对象,它的作用与CreatePen函数完全一样,只是画笔的3个属性不是直接出现在函数参数中,而是通过一个LOGPEN结构间接地给出。 BOOL CreatePenIndirect(LPLOGPEN lpLogPen); 此函数用由LOGPEN结构指针指定的相关参数创建画笔。LOGPEN结构如下: Type
25、def struct tagLOGPEN { UINT lopnStyle //画笔风格 POINT lopnWidth; //POINT结构的y不起作用,而用x表示画笔宽度 COLORREF lopnColor //画笔颜色 }LOGPEN 注 意: 1、当修饰画笔的宽度大于1个像素时,画笔的风格只能取PS_NULL、PS_SOLID或PS_INSIDEFRAME,定义为其它风格不会起作用。 2、画笔的创建工作也可在画笔的构造函数中进行,它具有下列原型: CPen(int nPenStyle,int nWidth,CO
26、LORREF crColor); 例5.5 用颜色为蓝色,宽度为8个像素的实心画笔,画线和画椭圆。 (1)创建一个单文档的应用程序,名为:画笔 (2)利用ClassWizard将WM_PAINT消息映射到视图类(View)中,并加代码: void CMyView::OnPaint() { CDC *pDC=GetDC();//获得显示设备环境DC的指针pDC CPen newPen;//定义图笔对象 //生成一支颜色为蓝色,宽度为8个像素的实心画笔 newPen.CreatePen(PS_SOLID,8,RGB(0,0,255)); //将创建的画笔选入内存DC,
27、同时暂停挤出并保存原画笔 CPen *poldpen=pDC->SelectObject(&newPen); pDC->MoveTo(10,10);//调用MoveTo函数,定位于点(10,10) pDC->LineTo(100,100);//调用LineTo函数,画线至点(100,100) pDC->Ellipse(120,120,160,160);//调用画椭圆函数Ellipse //恢复内存DC中原有的画笔 pDC->SelectObject(poldpen); ReleaseDC(pDC);//释放显示DC } (3)编译运行,结果见图5.3.2所示。
28、 注 意:默认的画笔为黑色、一个像素的宽度、 实心。默认的画刷为白色。例如:例5.4中的 OnPaint()函数中没有创建画笔,则用默认的画 笔绘图。 5.3.2 颜色画笔运行结果 5.3.2 画刷CBrush类 CBrush 类封装了一个Window GDI画刷,并且提供了用于操作CBrush对象的若干方法。画刷可设置画刷的色彩和区域填充的绘图方法。在使用画笔、画刷之前,首先必须构造画笔、画刷
29、对象,有2种构造方法。 (1)构造和初始化对象都在带参数的构造函数中一步完成,如: CBrush newBrush(RGB(0,0,255));//蓝色画刷 (2)构造和初始化分2步完成,构造由不带参数的构造函数完成,而初始化由初始化函数完成,如:CBrush newBrush; newBrush.CreateSolidBrush(RGB(0,0,255)); (3)CBrush类根据画刷属性提供了相应的创建函数,例如创建填充画刷和填充样式画刷函数为:CreateSolidBrush和CreateHatchBrush,它们的原型如下: BOOL CreateSolidBrush(C
30、OLORREF crColor);//创建填充色画刷 BOOL CREATEhATCHbRUSH(int nIndex,COLORREF crColor);//创建填充样式画刷 参 数: nIndex 用于指定画刷的内部填充样式 crColor表示画刷的填充色 与画笔类似,画刷也有一个LOGBRUSH逻辑结构用于画刷属性的定义,并通过CBrush的成员函数CreateBrushIndirect来创建,其原型如下: BOOL CreateBrushIndirect(const LOGBRUSH *lpLogBrush); 参 数:LOGBRUSH结构如:Typedef
31、 struct tagLOGBRUSH { UINT lbStyle; //风格 COLORREF lbColor; //填充色 LONG lbHatch; //填充样式 }LOGBRUSH; (4)画刷的创建工作也可在其构造函数中进行,它具有下列原型: CBrush(COLORREF crColor); CBrush(int nIndex,COLORREF crColor); CBrush(CBitma
32、p *pBitmap); (5)画刷也可用位图来指定其填充图案,但该位图应该是8*8像素,若畏途太大,Windows则只使用其左上角的8*8的像素。 (6)画刷仅对一些绘图函数有效,如:Ellipse、FillRect函数等。 例5.6 用颜色为红色、宽度为6个像素的实心画笔画矩形,并用绿色画刷填充矩形内部。 (1)创建一个单文档的应用程序,名为:画刷 (2)利用ClassWizard将WM_PAINT消息映射到视图类(View)中,并加代码: void CMyView::OnPaint() { CDC *pDC=GetDC();//获得显示设备环境DC的指针pDC
33、CPen newPen; //定义画笔对象 //生成一支颜色为红色,宽度为6个像素的实心画笔 newPen.CreatePen(PS_SOLID,6,RGB(255,0,0)); CBrush newBrush; //定义画刷对象 newBrush.CreateSolidBrush(RGB(0,255,0));//绿色画刷 //将创建的画笔选入内存DC,同时暂时挤出并保存原画笔 CPen *poldpen=pDC->SelectObject(&newPen); //将创建的画刷选入内存DC,同时暂时挤出并保存原画刷 CBrush *poldb
34、rush=pDC->SelectObject(&newBrush); pDC->MoveTo(10,10);//调用MoveTo函数,定点到点(10,10) pDC->LineTo(100,100);//调用LineTo函数,画线到点(100,100) //调用画矩形函数Rectangle pDC->Rectangle(120,120,200,200); //恢复内存DC中原有的画笔 pDC->SelectObject(poldpen); //恢复内存DC中原有的画刷 pDC->SelectObject(poldbrush); //释放显示DC Relea
35、seDC(pDC); } 图5.3.3 红色画笔、绿色画刷 (3)编译运行,结果如图5.3.3所示。 画刷的属性通常包括填充色、填充图案和填充样式3种。画刷的填充色和画笔颜色一样,都是使用COLORREF颜色类型,画刷的填充图案通常是用户定义的8*8位图,而填充样式往往是CDC内部定义的一些特性,它们都是以HS_为前缀的标识,如表5.4所示。 5.4 坐标映射 在某个设备环境中绘制一个高为100个像素,宽也为100个像素的方块,语句如下: pDC->Rec
36、tangle(CRect(0,0,100,100)); // Rectangle绘制矩形,长方形 表5.4 画刷的填充样式 标识 填充样式 HS_BDIAGONAL 向下点斜线 HS_CROSS 方格 HS_DIAGCROSS 向下点斜线与斜线复合 HS_FDIAGONAL 向上点斜线 HS_HORIZONTAL 横条 HS_VERTICAL 竖条 由于默认的映射模式是MM_TEXT,其逻辑坐
37、标(在各种映射模式下的坐标)和设备坐标(显示设备或打印设备坐标系下的坐标)相等。因此这个方块在1024*768的显示器上看起来要比在640*480的显示器上显得小一些,而且若将它打印在600dpi精度的激光打印机上,这个方块就会显得更小了。为了能保证打印的结果不受设备的影响,Windows定义了一些映射模式,如表5.5所示,这些映射决定了设备坐标和逻辑坐标之间的关系。 表5.5 映 射 模 式 映射模式 含义 MM_TEXT
38、 每个逻辑单位等于一个设备像素,x向右为正,y向下为正 MM_HIENGLISH 每个逻辑单位为0.001英寸,x向右为正,y向上为正 MM_LOENGLISH 每个逻辑单位为0.01英寸,x向右为正,y向上为正 MM_HIMETRIC 每个逻辑单位为0.01mm,x向右为正,y向上为正 MM_LOMETRIC 每个逻辑单位为0.1mm,x向右为正,y向上为正 MM_TWIPS每个逻辑单位为一个点的1/20(一个点是1/72英寸),x向右为正,y向上为正 MM_ANISOTRPIC x,y 可变比例 MM_ISOTROPIC
39、 x,y 等比例 这样,我们就可以通过调用CDC::SetMapMode(int nMapMode)来设置相应的映射模 式。例如:若将映射模式设置为MM_LOMETRIC,那么不管在什么设备中调用上述语句,都将显示出20*20mm的方块。而MM_ISOTROPIC映射模式下:纵横比总是1:1,也就是说,无论比例因子如何变化,圆总是圆的。但,MM_ANISOTROPIC映射模式下,x和y的比例因子可以独立地变化,即圆可以被拉扁成椭圆形状。在映射模式MM_ANISOTROPIC和MM_ISOTROPIC中,常常可以调用CDC::SetWindowExt(设置窗口大小)和CD
40、C::SetViewportExt(设置视口大小)函数来设置所需要的比例因子。 “窗口”和“视口”的概念往往不易理解。所谓“窗口”,可以理解是一种逻辑坐标下的窗口,而“视口”是我们实际看到的那个窗口,也就是设备坐标下的窗口,根据“窗口”和“视口”的大小就可以确定x和y的比例因子,它们的关系如下: x比例因子=视口x大小/窗口x大小 y比例因子=视口y大小/窗口y大小 例5.7:将一个椭圆绘制在视窗中央,且当视图的大小发生改变时,椭圆的形状也会 随之改变。(通过设置窗口和视口大小来改变显示的比例) 1)建一个单文档应用程序,名为:椭圆的绘制 2)在View类的OnDra
41、w函数里加如下代码: void CMyView::OnDraw(CDC* pDC) { //CMyDoc* pDoc = GetDocument(); //ASSERT_VALID(pDoc); CRect rectClient; //定义矩形对象 GetClientRect(rectClient); //获得当前窗口的客户区大小 //设置MM_ANISOTROPIC映射模式,x,y可变比例,见表5.5所示 pDC->SetMapMode(MM_ANISOTROPIC); pDC->SetWindowExt(1000,1000);
42、//设置窗口范围(大小) pDC->SetViewportExt(rectClient.right,-rectClient.bottom);//设置视口范围(大小) pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2);//设置视口原点 pDC->Ellipse(CRect(-500,-500,500,500));//椭圆的4个坐标点 // TODO: add draw code for native data here } 3)编译运行,当你改变窗口大小,椭圆也随之改变,见图5.4.1所示。 说 明:
43、 SetMapMode该函数设置指定设备环境的映射方式, 映射方式定义了将逻辑单位转换为设备单位的度量单 位,并定义了设备的X、Y轴的方向。 函数原型:int SetMapMode(HDC hdc, int fnMapMode); 参 数:hdc:指向设备环境的句柄。 fnMapMode:指定新的映射方式,此参数可 以是上面表5.5列出的任何一个值。 5.5 CPoint、CSize和CRect 图5.4.1 绘制椭圆 在图形绘制操作中,常常需要使用MFC 中的CPoint(点)、CSize(大小)和CR
44、ect(矩形)等简单数据类。它们是对Windows的POINT、SIZE和RECT结构的封装,因此它们可以直接使用各自结构的数据成员,如下所示: typedef struct tagPOINT { LONG x; //点的x坐标 LONG y; //点的y坐标 }POINT; Typedef struct tagSIZE { int cx; //水平大小 (表示矩形的宽度) int cy; //垂直大小 (表示矩形的高度) }SIZE; typedef struct tagRECT { LONG left; //矩形左上角点的
45、x坐标 LONG top; //矩形左上角点的y坐标 LONG right; //矩形右下角点的x坐标 LONG bottom; //矩形右下角点的y坐标 }RECT; 1、CPoint,CSize和CRect类的构造函数 CPoint类带参数的常用构造函数原型如下: CPoint(int initX,int initY); CPoint(POINT initPt); 参 数: initX和initY分别用于指定CPoint的成员x和y的值。 initPt用于指定一个POINT结构或CPoint对象来初始化CPoint的成员。
46、 CSize类带参数的常用构造函数原型如下: CSize(int initCX,int initCY); CSize(SIZE initSize); 参 数: initCX和initCY用于分别设置CSize的cx和cy成员。 initSize用于指定一个SIZE结构或CSize对象来初始化CSize的成员。 CRect类带参数的常用构造函数原型如下: CRect(int l,int t,int r,int b); CRect(const RECT &srcRect); CRect(LPCRECT lpSrcRect); CRect(POINT point,SIZE si
47、ze); CRect(POINT topLeft,POINT bottomRight); 参 数: l,t,r,b分别用于指定CRect的left,top,right和bottom成员的值。 srcRect、lpSrcRect分别用一个RECT结构或指针来初始化CRect的成员。 Point用于指定矩形的左上角位置。Size用于指定矩形的长度和宽度。 topLeft和bottomRight分别用于指定CRect的左上角和右下角的位置。 2、CRect类的常用操作 由于一个CRect类对象包含用于定义矩形左上角和右下角点的成员变量,因此在传递LPRECT、LPCRECT或
48、RECT结构作为参数的任何地方,都可以使用CRect对象来代替。 当构造一个CRect 时,要使它符合规范。也就是说,使其left小于right,top小于bottom;例如,若左上角为(20,20),而右下角为(10,10),那么定义的这个矩形就不符合规范。一个不符合规范的矩形,CRect的许多成员函数都不会有正确的结果。因此,常常使用CRect::NormalizeRect函数使一个不符合规范的矩形合乎规范。 CRect类的操作函数有很多,这里只介绍矩形的扩大、缩小以及2个矩形的“并”和“交”操作,更多的常用的成员函数如表5.6所示: 表5.6 CRect类常用的成员函
49、数 成员函数 功能说明 int Width()const; 返回矩形的宽度 int Height()const; 返回矩形的高度 CSize Size()const; 返回矩形左下角的点坐标 CPoint &BottomRight 返回矩形右下角的点坐标 CPoint CenterPoing()const 返回CRect的中点坐标 BOOL IsRectEmpty()const 如果一个矩形的宽度或高度是0或负值,则称这个矩形为空, 返回TRUE BOOL IsRectNull()
50、const; 如果一个矩形的上、左、下和右边的值都等于0,则返回TRUE BOOL PtInRect(POINT point)const; 如果点point位于矩形中(包括点在矩形的边上)则 返回TRUE void SetRect(int x1,int y1,int x2,int y2);将矩形的各边设为指定的值,左上角点为(x1,y1), 右下角点为(x2,y2) void SetRectEmpty(); 将矩形的所有坐标设置为0 void NormalizeRect(); 使矩形符合规范如:左






