1、1第 8 章 GDI 编程 1-绘图详细介绍了 GDI 绘图,希望对你有帮助:GDI(Graphics Device Interface,图形设备接口)是 Windows 操作系统的传统图形子系统,负责与设备无关的图形绘制,Win32 API 为应用程序提供了丰富的绘图函数和功能,MFC 对它们进行了 C+类封装,参见图 8-1。Windows 应用程序MFCWin32 APIGDI+执行程序 用户界面(User)图形子系统(GDI )设备驱动程序 内核(Kernel) 图形驱动程序硬件抽象层( HAL)计算机硬件图 8-1 GDI 与 Windows 操作系统(其中彩色部分为操作系统)传统
2、GDI 是随 Windows 1.0 于 1985 年 11 月推出的,新式 GDI+则是随 Windows XP于 2001 年 10 月推出的 GDI 的改进版,增加了 混色、渐变画刷、样条曲线、矩阵变换、图像处理、持久路径等新功能。随 Windows Vista 及.NET 框架 3.0 微软于 2006 年 11 月又推出了基于 DirectX 和.NET 框架的全新图形子系统 WPF(Windows Presentation Foundation,视窗显示/展现基础) ,它统一了桌面和浏览器等客户端应用程序的图形界面,采用 XAML 声明式编程,将用户界面的设计和编程彻底分离开来,是
3、 Windows 的下一代GUI 显示系统。本书从第 8 章到第 11 章,将详细讨论如何使用 GDI 进行传统的 Windows 图形编程,包括绘图、文字、图像、动画、图标、图元文件和打印等内容。GDI+ 是建立在 GDI 之上的,计划在第 14 和 15 章中作简单介绍。WPF 则是以.NET 框架为基础的,准备在第 19 上和 20 章中再加以讨论。在 MFC 应用程序中,绘图一般在视图类的(屏幕/ 打印机)绘图消息响应函数OnDraw 中进行,例如:void CDrawView:OnDraw(CDC* /*pDC*/) CDrawDoc* pDoc = GetDocument();AS
4、SERT_VALID(pDoc);if (!pDoc)2return;/ TODO: 在此处为本机数据添加绘制代码每次需要重绘窗口时(如程序启动、窗口大小改变、全部或部分窗口重现、程序员调用函数 RedrawWindow 或 Invalidate/UpdateWindow) ,应用程序框架都会调用此 CWnd 消息响应成员函数(的覆盖)来绘制窗口客户区。在 Windows 中,绘图一般在框架窗口的客户区(对应于视图类 C*View)进行,使用的是封装在 MFC 的设备上下文(Device-Context,DC)类 CDC 中的各种绘图函数。在绘图前,一般需先得到客户区大小和 CDC 对象、设置
5、绘图颜色,然后再根据文档数据或用户操作来绘制各种图形。8.1 几何对象的结构和类为了使用绘图函数,应该先了解绘图所用到的几种表示几何对象的结构和类,包括点、大小和矩形,其中常用的是点和矩形。这些结构和类被分别定义在头文件 windef.h 和 afxwin.h中。MFC 中的几何对象类都是独立的类(不是 CObject 的派生类) ,是对 API 中对应结构的 C+封装,参见图 8-2。8.1.1 点点(point)在 API 中的结构为 POINT,对应的 MFC 类为 CPoint。1点结构 POINTAPI 中的点数据结构 POINT 用来表示一点的 x、y 坐标:typedef str
6、uct tagPOINT LONG x; LONG y; POINT;其中,类型 LONG(32 位整数)的定义为:typedef long LONG;2点类 CPointMFC 中的点类 CPoint 为一个没有基类的独立类,封装了 POINT 结构,有成员变量 x图 8-2 GDI 几何对象的结构与类3和 y,其构造函数有 5 种:CPoint( ); / 默认CPoint( int initX, int initY ); / 常用CPoint( POINT initPt );CPoint( SIZE initSize );CPoint( LPARAM dwPoint ); / 低字设为
7、x、高字设为 yCPoint 类还定义了 4 个平移和设置的成员函数:void Offset(int xOffset, int yOffset);void Offset(POINT point);void Offset(SIZE size);void SetPoint(int X, int Y);另外,CPoint 类还重载了+、-、+=、-=、=、!= 等运算符来支持 CPoint 对象和CPoint、 POINT、SIZE 对象之间的运算。8.1.2 大小大小(size ,尺寸)在 API 中的结构为 SIZE,在 MFC 中的类为 CSize。1大小结构 SIZE大小结构 SIZE 用来
8、表示矩形的宽 cx 和高 cy:typedef struct tagSIZE LONG cx; LONG cy; SIZE;2大小类 CSizeMFC 中的大小类 CSize 也为一个没有基类的独立类,封装了 SIZE 结构,有成员变量cx 和 cy,其构造函数也有 5 种:CSize( );CSize( int initCX, int initCY );CSize( SIZE initSize );CSize( POINT initPt );CSize( DWORD dwSize ); / 低字设为cx、高字设为 cyCSizet 类也重载了+、-、+=、 -=、=、!= 等运算符来支持 C
9、Size 对象和CSize、 POINT、SIZE、RECT 对象之间的运算。8.1.3 矩形矩形(rectangle)在 API 中的结构为 RECT,在 MFC 中的类为 CRect。41矩形结构 RECTAPI 中的矩形结构 RECT 定义了矩形的左上角与右下角的坐标:typedef struct tagRECT LONG left; LONG top; LONG right; LONG bottom; RECT;2矩形类 CRectMFC 中的矩形类 CRect 也为一个没有基类的独立类,封装了 RECT 结构,有成员变量left、 top、right 和 bottom,其构造函数有
10、6 种:CRect( ); / 默认CRect( int l, int t, int r, int b ); / 常用CRect( const RECTCRect( LPCRECT lpSrcRect );CRect( POINT point, SIZE size );CRect( POINT topLeft, POINT bottomRight );CRect 类重载了=,+、-,+=、-=,=、!=,int Height( ) const;CSize Size( ) const;CPointCPointCPoint CenterPoint( ) const;void SwapLeftRig
11、ht();BOOL IsRectEmpty( ) const;BOOL PtInRect( POINT point ) const;void SetRect( int x1, int y1, int x2, int y2 );void SetRect(POINT topLeft, POINT bottomRight);void OffsetRect(int x, int y);void MoveToXY(int x, int y);3判断点是否在矩形中有时需要判断某点(如鼠标位置)是否在某一矩形区域(如控件)中,这可以调用CRect 类的 PtInRect 函数来做:BOOL PtInRect
12、( POINT point ) const;该函数当点 point 在其矩形区域内时,返回真。注意,该矩形区域不包括矩形的右边界和底边界。例如:CRect rect( 10, 10, 371, 267 );5void CDrawView:OnLButtonUp(UINT nFlags, CPoint point) / TODO: 在此添加消息处理程序代码和 /或调用默认值if ( rect.PtInRect( point ) ) . .CView:OnLButtonUp(nFlags, point);8.1.4 获得客户区大小绘图一般都是在框架窗口的客户区(对应于视图类)进行,而客户区的大小在
13、运行时可由用户动态改变,为了使绘制的图形能随窗口大小而自动改变,需先得到当前客户区大小的数据(宽和高) 。获取客户区大小的方法有如下两种:1OnSize获取客户区大小的第一种方法是通过消息响应函数 OnSize 中获得。可利用属性窗口的消息页,为视图类添加 WM_SIZE 消息的响应函数 OnSize。该函数会在窗口第一次显示或窗口大小被改变时被系统调用。其输入参数中的 cx 和 cy 就是当前客户区的宽和高,可将它们赋值给类变量(如 m_iW 和 m_iH)供绘图时使用。例如:void CDrawView:OnSize(UINT nType, int cx, int cy) CView:On
14、Size(nType, cx, cy);/ TODO: 在此处添加消息处理程序代码m_iW = cx; m_iH = cy;其中,nType 的值为: SIZE_MAXIMIZED(窗口已被最大化) SIZE_MINIMIZED(窗口已被最小化) SIZE_RESTORED(窗口已被改变大小) SIZE_MAXHIDE(其他窗口被最大化) SIZE_MAXSHOW(其他窗口从最大化还原)62GetClientRect获取客户区大小的第二种方法是调用窗口类的获取客户区矩形成员函数 GetClientRect来得到。具体做法是,在绘图前定义一个矩形结构变量 rect,然后再调用 CWnd 类的成员
15、函数 GetClientRect 来得到当前客户区矩形的数据,该函数的原型为:void GetClientRect( LPRECT lpRect ) const;其中,矩形结构的右(right)与底(bottom)就是客户区的宽与高(其左 left 与顶 top 都为0) 。例如:RECT rect;GetClientRect(int iW = rect.right, iH = rect.bottom;8.2 绘图环境 DC 在 Windows 中,绘图包括绘制图形、显示位图和输出文字,它们都需要使用绘图环境DC(Device-Context, 设备上下文) 。MFC 将 DC 结构和所有的绘
16、图函数、绘图对象的访问函数、绘图模式与参数的设置函数都封装到了 CDC 类中。8.2.1 DC结构DC 是 Windows 为设备无关的图形绘制而定义的一种数据结构,包含了一组图形对象及关联属性和若干影响输出的图形模式和绘图参数。所有的 GDI 绘图操作,都是采用 DC中的当前图形对象作为绘图工具,并且都是在 DC 中的当前图形模式下使用当前的绘图参数进行的。1图形对象Windows 的图形对象(graphic object)包括画线状图的笔、绘制和填充面状图的刷、用于复制和滚动部分屏幕的位图、定义可用颜色的调色板、用于裁剪和其他操作的区域、用于绘制和画图操作的路径、及用于输出文字的字体,参见
17、表 8-1。图像对象所对应的MFC 类将在 8.3.6 中介绍,其中笔和刷在 8.3.3 和 8.3.4 中介绍,字体在 9.2 中介绍。表 8-1 图形对象及 DC 的默认值7图形对象 关联属性 DC 默认值笔 风格、宽度、颜色 实心、单像素、黑色刷 风格、颜色、图案、原点 实心、白色、单色、(0, 0)位图大小(字节) 、尺寸(像素)、颜色格式、压缩方式等无调色板 颜色与大小(或颜色数) 20 种标准系统色区域 定位与尺寸 窗口矩形路径 形状 无字体字体名、宽、高、粗细、字符集等system(宋体) 、7、16、700(粗体) 、GB2312_CHARSET2图形模式图形模式(graphi
18、cs mode)用于确定颜色如何混合、输出在何处出现、输出如何缩放等,参见表 8-2。表 8-2 图形模式及 DC 的默认值图形模式 描述 DC 默认值 介绍章节映射定义图形输出如何从逻辑(或世界)空间映射到窗口、屏幕或打印机纸,即坐标体系文本(MM_TEXT) ,即设备坐标(单位为像素、x 向右、y 向下)8.4.1绘图对笔、刷、位图和文本操作,定义前景色如何与已存在的窗口或屏幕颜色混合覆盖(R2_COPYPEN) 8.5.2背景对位图和文本操作,定义背景色如何与已存在的窗口或屏幕颜色混合不透明(OPAQUE) 8.5.1拉伸定义在位图被压缩(或缩小)时,定义位图颜色如何与已存在的窗口或屏幕
19、颜色混合存黑去白(BLACKONWHITE)9.3.3多边形填充 定义刷图案如何用来填充复杂区域 交替(ALTERNATE) , 8.5.38的内部 即按奇偶规则填充3图形参数除了图形对象和图形模式外,DC 中还保存有当前的笔位置(默认值为坐标原点) 、背景色(默认为白色) 、文本色(默认为黑色) 、文本对齐(默认为左顶) 、画弧方向(逆时针)等绘图参数。虽然 DC 是一种结构,但是 Windows 不允许应有程序的代码直接访问它。程序员必须通过调用各种对应的 Set*和 Get*函数以及 Select*来设置和获取其中的对象、模式和参数。8.2.2 CDC类CDC 类是 MFC 对 DC 结
20、构及其相关绘图和状态设置函数的 C+类封装。CDC 是CObject 的直接派生类,CDC 类自己也有若干派生类,其中包括:窗口客户区 DC 所对应的 CClientDC 类、 OnPaint 和 OnDraw 消息响应函数的输入参数中使用的 CPaintDC 类、图元文件对应的 CMetaFileDC 类和整个窗口所对应的 CWindowDC 类,参见图 8-3。在普通的 MFC 绘图中,一般直接使用 CDC 类即可。CDC 类中有许多成员函数,可以用来设置各种绘图环境、属性和参数,以及绘制各种图形和图像等,将在后面陆续加以介绍。1获得 DC在 OnDraw 函数中应该使用输入参数 pDC,
21、在其他函数中则可调用从 CWnd 类继承的成员函数 GetDC 来获得当前窗口(如客户区 /视图类)DC 的指针,该函数的原型为:CDC* GetDC( );注意,每次从 OnDraw 函数的输入参数或调用 GetDC 所获得的 DC,都是一个全新的临时默认 DC,具有默认的绘图环境和设置。它不能用类变量来长期保存,而且原来选入的各种 GDI 对象全都被作废、原来设置的各种状态也失效,一切都必须从头再来。图 8-3 DC 类92释放 DC因为 Windows 限制可用 DC 的数量,所以 DC 属于稀缺的公用资源。因此,对每次获得的 DC,在使用完成后必须立即释放。从 OnDraw 函数的输入
22、参数 pDC 获得的 DC,在该函数运行结束后,系统会自动释放。但由 GetDC 所获得的 DC,则必须自己来手工释放,这可以通过调用从 CWnd 类继承的成员函数 ReleaseDC 来完成。该函数的原型为:int ReleaseDC( CDC* pDC ); / 成功返回非 0例如:void CDrawView:OnLButtonUp(UINT nFlags, CPoint point) CDC* pDC = GetDC(); / 获取 DCpDC-SelectObject( / 选入笔pDC-Rectangle( / 绘制矩形ReleaseDC(pDC); / 释放 DCCView:On
23、LButtonUp(nFlags, point);3安全 DC句柄可以用 CDC 类的成员函数 GetSafeHdc 来获取 DC 所对应窗口(如客户区)的安全 DC句柄,该函数的原型为:HDC GetSafeHdc();与用 GetDC 函数所得到的临时 DC 不同,该安全 DC 句柄在窗口的存在期间内一直是有效的。例如,可先定义类变量 HDC m_hDC;,再在适当的地方给它赋值 m_hDC = GetDC()-GetSafeHdc();,然后就可以放心地使用了。还可以使用 CDC 类的成员函数 Attach 来将一空 CDC 对象与此安全 DC 句柄连接在一起,该函数的原型为:BOOL
24、Attach(HDC hDC); / 成功返回非 0104屏幕 DC可以以 NULL 为输入参数,调用全局的 API 函数 GetDC:HDC GetDC(HWND hWnd);来可获取屏幕 DC 的句柄。例如:HDC hdc = :GetDC(NULL); / 获取屏幕 DC 的句柄Ellipse(hdc, 0, 0, 150, 100); / 用 API 函数在屏幕左上角画一椭圆也可以利用 CDC 类的成员函数 Attach,将屏幕 DC 的句柄选入自定义的 CDC 类中,来 构造屏幕 CDC 类的对象。例如:HDC hdc = :GetDC(NULL); / 获取屏幕 DC 的句柄CDC
25、 sDC; / 定义屏幕 DC(空)对象sDC.Attach(hdc); / 粘上屏幕 DC 句柄sDC.Ellipse(0, 0, 150, 100); / 在屏幕左上角画一椭圆8.3 绘图颜色与工具在 Windows API 中用 4 个字节的双字来定义颜色类型 COLORREF,有红(Red)绿(Green )蓝(Blue)三个字节分量,可用 RGB 宏来为颜色赋值。在 GDI 中有画线状图的笔(pen) 、画填充图的刷(brush ) 、画文字的字体(font)等绘图工具。而 GDI 中使用的颜色种类则有 4 种之多,它们分别是像素所对应的点色、笔所对应的线色、刷所对应面色、文字所对应
26、的文本色。其中的像素和文本色,可以通过调用对应的专门函数来设置和获取。而笔和刷的颜色,则必须先利用颜色参数创建笔和刷对象,然后调用通用的选择对象函数SelectObject 将笔、刷等绘图工具选入 DC,再利用 DC 来绘制各种颜色的图形。8.3.1 颜色Windows 中的颜色一般用 4 个字节表示( 0BGR(整数序)或 RGB0(字节序) ,因为Intel CPU 的低位字节在前) ,Win32 API 中定义了一个专门表示颜色索引值的变量类型COLORREF( windef.h):typedef DWORD COLORREF; / 0x00bbggrr和一个由红绿蓝三原色构造颜色值的宏
27、 RGB(wingdi.h ):11#define RGB(r,g,b)(COLORREF)(BYTE)(r)|(WORD)(BYTE)(g)SetPixel(10, 10, RGB(0, 255, 0);另外,还可以用 CDC 的成员函数COLORREF GetPixel( int x, int y ) const;COLORREF GetPixel( POINT point ) const;来获得指定点(x, y)或 point 的颜色。例如:COLORREF col;col = pDC-GetPixel(10, 10);128.3.3 线色(笔)在 Windows 中,线状图必须用笔(
28、pen)来画,所以线的颜色就由笔色来确定。在MFC 中,笔的属性和功能由 CPen 类提供(CPen 是 CGDIObject 的派生类) 。笔的创建与使用的步骤为:1创建笔对象创建 CPen 类笔对象的方法有如下两种: 使用非默认构造函数创建初始笔:CPen( int nPenStyle, int nWidth, COLORREF crColor );其中: nPenStyle 为笔的风格,可取值见表 8-3。表 8-3 笔风格 nPenStyle 值符号常量 数值 风格名称 线例PS_SOLID 0 实心PS_DASH 1 虚线PS_DOT 2 点线PS_DASHDOT 3 虚点线PS_D
29、ASHDOTDOT 4 虚点点线PS_NULL 5 空笔PS_INSIDEFRAME 6 框内注意:14 号笔风格只是在笔宽=0 或 1 时有效,笔宽1 时总为实心的。 nWidth 为笔宽,与映射模式有关,使用默认映射时为像素数,若 nWidth = 0,则不论什么映射模式,笔宽都为一个像素。 crColor 为笔的颜色值。默认的笔为单像素宽的黑色实心笔。例如:CPen* pGrayPen = new CPen(PS_SOLID, 0, RGB(128, 128, 128);CPen grayPen(PS_SOLID, 0, RGB(128, 128, 128); 使用成员函数 Create
30、Pen(多次)创建笔:13BOOL CreatePen( int nPenStyle, int nWidth, COLORREF crColor );可先用 CPen 类的默认构造函数创建一个空笔对象,然后再调用 CreatePen 创建具有新内容的笔,例如:CPen grayPen;grayPen.CreatePen(PS_SOLID, 0, RGB(128, 128, 128);不过在用 CreatePen 创建新笔之前,必须先调用 DeleteObject 函数删除笔对象的内容。该函数是 CPen 的基类 CGDIObject 的成员函数,下面是它的原型:BOOL DeleteObjec
31、t( );2选笔入 DC为了能使用我们自己所创建的笔对象,必须先将它选入 DC,这可以调用设备上下文类 CDC 的成员函数 SelectObject 来完成:CPen* SelectObject( CPen* pPen );该函数的返回值为指向原来笔对象的指针(一般将其保存下来,供下次选出新笔时使用) 。例如:pOldPen = pDC-SelectObject(另外,Windows 中有一些预定义的笔对象(参见表 8-4) ,可用 CDC 的另一成员函数SelectStockObject 将其选入 DC,其函数原型为:virtual CGdiObject* SelectStockObject
32、( int nIndex );表 8-4 预定义笔符号常量 数值 笔WHITE_PEN 6 白色笔BLACK_PEN 7 黑色笔NULL_PEN 8 空笔DC_PEN 19 DC 笔其中,DC 笔为单色实心笔,默认为黑色。是从 Windows NT/2000 开始新引进的,可用于直接设置笔色,参见本小节后面的第 6 部分。例如:pDC-SelectStockObject(BLACK_PEN);143绘制线状图在将笔对象选入 DC 后,就可以使用 CDC 类中的绘图函数,利用 DC 中的笔对象,来画线状图及面状图的边线。如果不创建和选入笔对象,则使用的是 DC 中的默认笔,为单像素宽的实心黑色笔
33、。Windows 中的线状图有直线、折线、矩形、 (椭)圆(弧)等,详见 8.4.3。4删除笔不能直接删除已使用过的笔对象,必须先将它从 DC 中释放出来后才能删除。释放的方法是装入其他的笔对象(一般是重新装入原来的笔对象) 。例如:pDC-SelectObject(pOldPen);删除笔对象的方法有如下几种: 删除笔内容:调用笔类 CDC 的成员函数 DeleteObject 删除笔的当前内容(但是未删除笔对象,以后可再用成员函数 CreatePen 在笔对象中继续创建新的笔内容) 。例如:pen.DeleteObject(); 删除笔对象:使用删除运算符 delete 将笔对象彻底删除,
34、例如 delete 。 自动删除:若笔对象为局部变量,则在离开其作用域时,笔对象会被系统自动删除。5例子下面为一段较完整地创建与使用笔的例子代码:CDC* pDC = GetDC(); / 获取 DCCPen pen, *pOldPen; / 定义笔对象和指针/ 创建 10 单位宽的绿色实心笔pen.CreatePen(PS_SOLID, 10, RGB(0, 255, 0);pOldPen = pDC-SelectObject( / 选入绿色笔pDC-Rectangle(10, 10, 100, 100); / 画矩形pDC-SelectObject(pOldPen); / 选出绿色笔pen
35、.DeleteObject(); / 删除绿色笔15/ 创建单像素宽的红色虚线笔pen.CreatePen(PS_DASH, 0, RGB(255, 0, 0);pOldPen = pDC-SelectObject( / 选入红色笔pDC-MoveTo(10, 10); pDC-LineTo(100, 100); / 画直线ReleaseDC(pDC); / 释放 DC6设置 DC笔颜色对 Windows NT/2000 及以上的版本,如果只需修改实心笔的颜色,而不需改变笔的粗细,则可以不用反复创建和选入新笔,而使用 CDC 类的成员函数 SetDCPenColor,来直接设置 DC 笔的颜色
36、:COLORREF SetDCPenColor( COLORREF crColor ); / 返回原颜色值对应的获取 DC 三笔颜色的成员函数为:COLORREF GetDCPenColor( ) const;不过这需要先调用 CDC 的成员函数 SelectStockObject 将 DC 笔选入 DC 后,才能使用SetDCPenColor 函数来设置 DC 中笔的颜色。例如:pDC-SelectStockObject(DC_PEN); / 选入 DC 笔pDC-SetDCPenColor(RGB(255, 0, 0); / 设置成红色8.3.4 面色(刷)在 Windows 中,面状图必
37、须用刷( brush)来填充,所以面色是由刷色来确定的。MFC 中的刷类为 CBrush(它也是 CGDIObject 的派生类) ,刷的创建与使用的步骤与笔的相似。1构造函数CBrush 类有 4 个构造函数,分别用于创建空刷、实心刷、条纹刷和图案刷: CBrush( ); / 创建一个刷的空对象 CBrush( COLORREF crColor ); / 创建颜色为 crColor 的单色实心刷 CBrush( int nIndex, COLORREF crColor ); / 创建风格由 nIndex 指定且颜色为crColor 的条纹( hatch,孵化/影线)刷,其中 nIndex
38、可取条纹风格(Hatch 16Styles)值见表 8-5 和图 8-4。表 8-5 条纹风格 nIndex 值符号常量 数值 风格HS_HORIZONTAL0 水平线HS_VERTICAL 1 垂直线HS_FDIAGONAL 2 正斜线HS_BDIAGONAL 3 反斜线HS_CROSS 4 十字线(正网格)HS_DIAGCROSS 5 斜十字线(斜网格)水平线 垂直线 正斜线 反斜线 十字线 斜十字线图 8-4 条纹刷的种类 CBrush(CBitmap* pBitmap); / 创建位图为 pBitmap 的图案(pattern )刷默认的刷为白色实心刷。2创建函数与构造函数相对应,CB
39、rush 类有多个创建不同类型刷的成员函数,如: BOOL CreateSolidBrush( COLORREF crColor ); / 创建(单色)实心刷 BOOL CreateHatchBrush( int nIndex, COLORREF crColor ); / 创建条纹刷 BOOL CreatePatternBrush( CBitmap* pBitmap ); / 创建图案刷3预定义刷预定义的刷对象见表 8-6 有:表 8-6 预定义刷符号常量 数值 刷WHITE_BRUSH 0 白刷(默认)17LTGRAY_BRUSH 1 亮灰刷GRAY_BRUSH 2 灰刷DKGRAY_BRU
40、SH 3 暗灰刷BLACK_BRUSH 4 黑刷HOLLOW_BRUSH 5 空刷NULL_BRUSH 5 空刷DC_BRUSH 18 DC 刷其中,DC 刷为单色实心刷,默认为白色。是从 Windows NT/2000 开始新引进的,可用于直接设置刷色,参见本小节后面的第 5 部分。3选入刷与笔一样,可以用函数 SelectObject 或 SelectStockObject 将自定义刷或预定义刷选入DC 中,供绘面状图时使用。如果未选入任何刷,则系统会使用 DC 中的默认刷来绘图,默认刷为白色实心刷。4例子下面是一个创建、选入并使用自定义实心刷的简单例子代码段:CRect rect(10,
41、 10, 210, 160);CBrush brush(RGB(0, 255, 0);CDC* pDC = GetDC();pDC-SelectObject(pDC-Rectangle(ReleaseDC(pDC);5设置 DC刷色对 Windows NT/2000 及以上的版本,如果只需修改实心刷的颜色,而不改变刷的种类和风格,则可以不用反复创建和选入新刷,而使用 CDC 类的成员函数 SetDCBrushColor,来直接设置 DC 刷的颜色:COLORREF SetDCBrushColor( COLORREF crColor ); / 返回原颜色值18对应的获取 DC 中刷颜色的成员函数
42、为:COLORREF GetDCBrushColor( ) const;与设置 DC 笔类似,也需要先调用 CDC 的成员函数 SelectStockObject 将 DC 刷选入 DC后,才能使用 SetDCBrushColor 函数来设置 DC 中刷的颜色。例如:pDC-SelectStockObject(DC_BRUSH); / 选入 DC 刷pDC-SetDCBrushColor(RGB(255, 0, 0); / 设置成红色8.3.5 文本色可使用 CDC 类的成员函数 SetTextColor/ GetTextColor 和 SetBkColor/ GetBkColor 来分别设置
43、/获取输出文本的前景色和背景色(默认的前景色为黑色,背景色为空):COLORREF GetTextColor( ) const;virtual COLORREF SetTextColor( COLORREF crColor );COLORREF GetBkColor( ) const; virtual COLORREF SetBkColor( COLORREF crColor );例如:pDC-TextOut(10, 10, L“Test text“);pDC-SetTextColor(RGB(0, 255, 0);pDC-TextOut(10, 30, L“Test text“);pDC-S
44、etBkColor(RGB(255, 0, 0);pDC-TextOut(10, 50, L“Test text“);输出结果如图 8-5 所示。8.3.6 绘图工具Windows 的绘图工具为各种 GDI 对象,被封装在 MFC 对应的 CGDIObject 派生类中。将 GDI 对象用 SelectObject 函数选入 DC后,就可利用对应的绘图工具进行图形绘制。1GDI 对象GDI 对象(绘图工具)有笔、刷、位图、字体、调色板、区域等,对应的 MFC 类为图 8-5 文本色例图 8-6 GDI 对象的类层次结构19CPen、CBrush、CBitmap、CFont 等。这些绘图工具对象
45、类都是 CGDIObject 的派生类,而CGDIObject 则是直接从 CObject 类派生的抽象基类,参见图 8-6。其中的 CPen 和 CBrush 类上面已经讲过;CBitmap 和 CFont 将在以后的位图和字体部分讲;调色板类 CPalette 的使用非常复杂,本书不做介绍;CRgn 为区域(region)类,对应于窗口中的一个矩形、多边形或(椭)圆区域,可用于移动、拷贝、合并、判断和裁剪,在 GDI 绘图部分也不讲解,但在 GDI+中会做简单的介绍。2选入函数可用 CDC 类的多态成员函数 SelectObject,将绘图工具对象选入 DC,以供绘图时使用:CPen* S
46、electObject( CPen* pPen );CBrush* SelectObject( CBrush* pBrush );virtual CFont* SelectObject( CFont* pFont );CBitmap* SelectObject( CBitmap* pBitmap );int SelectObject( CRgn* pRgn );CGdiObject* SelectObject( CGdiObject* pObject );8.4 画图在 Windows 中,绘图一般在视图窗口的客户区进行,使用的是设备上下文类 CDC 中各种绘图函数。为了达到理想的绘图效果,有
47、时需要先利用 CDC 类设置绘图所用的坐标系(映射模式)和各种绘图属性。8.4.1 映射模式与坐标系在 Windows 中,绘图都是在当前的映射模式( map mode)下(坐标系中)进行的。而当前映射模式可以用 CDC 类的成员函数 SetMapMode 来设置。1默认映射模式映射模式影响所有的图形和文本绘制函数,它定义(将逻辑单位转换为设备单位所使20用的)度量单位和坐标方向,Windows 总是用逻辑单位来绘图。默认情况下,绘图的默认映射模式为 MM_TEXT,其绘图单位为像素(只要不打印输出,屏幕绘图使用该模式就够了) 。若窗口客户区的宽和高分别为 w 和 h 像素,则其 x 坐标是从
48、左到右,范围为 0 w-1;y 坐标是从上到下,范围为 0 h-1,参见图 8-7。图 8-7 默认的 MM_TEXT 图 8-8 非自定义且非 MM_TEXT 映射映射模式下的窗口坐标系 模式下的(初始)窗口坐标系(注意 y 在当前窗口中的坐标值为负)2设置映射模式可使用 CDC 类的成员函数 GetMapMode 和 SetMapMode 来获得和设置当前映射模式:int GetMapMode( ) const; / 返回当前的映射模式virtual int SetMapMode( int nMapMode ); / 返回先前的映射模式映射模式 nMapMode 的取值见表 8-7。表 8
49、-7 映射模式的 nMapMode 取值与含义符号常量 数值 x 方向 y 方向 逻辑单位MM_TEXT 1 向右 向下 像素MM_LOMETRIC 2 向右 向上 0.1 mmMM_HIMETRIC 3 向右 向上 0.01 mmMM_LOENGLISH 4 向右 向上 0.01 inMM_HIENGLISH 5 向右 向上 0.001 inMM_TWIPS 6 向右 向上 1/1440 in MM_ISOTROPIC 7 自定义 自定义 自定义21MM_ANISOTROPIC 8 自定义 自定义 自定义其中,in 为英寸,1 in = 2.54 cm;twips(缇)是一种打印标准单位;isotropic(各向同性的),指 x 与 y 方向的单位相同;和 anisotropic(各向异性的) ,则是指 x 与 y 方向的单位可不同。可见,除了两种自定义映射模式外,x 方向都是向右,y 方向也只有 MM_TEXT 的向下,其余的都是向上,与数学上坐标系一致,参见图