Windows的GDI(设备图形接口),提供了绘图的基本工具,如:画点、线、多边形、位图以及文本输出等。MFC的设备环境类CDC封装了全部的绘图函数,使得绘制的图形即可以显示,又可以打印。
概述
Visual C++的CDC(Device Context,设备环境)类是MFC中最重要的类之一,它封装了 绘图所需要的操作,是用户编写图形和文字处理程序必不可少的。当然,绘制图形和文字时还必须指定相应的设备环境。设备环境是由Windows保存的一个数据结构,该结构包含应用程序向设备输出时所需要的信息。
1、 设备环境类CDC
设备环境是由Windows保存的一个数据结构,该结构包含应用程序向设备输
出时所需要的信息,例如:图形是在屏幕上显示还是通过打印机输出。为了能让用户使用一些特殊的设备环境,基类CDC还派生了以下各类:
(1)CPaintDC类,此类比较特殊,它的构造函数和析构函数都是针对OnPaint进
行的。用户一旦获得相关的CDC指针,就可以将它当做任何设备环境(包括屏幕、打印机)指针来使用,CPaintDC类的构造函数会自动调用BeginPaint,而它的析构函数则会自动调用EndPaint。
(2)CClientDC和CWindowDC
A、CClientDC只能在窗口的客户区(不包括边框、标题栏、选单栏以及状态栏)进行绘图,点(0,0)通常指的是客户区的左上角。其构造函数调用GetDC,析构函数调用ReleaseDC函数
B、CWindowDC允许在窗口的任意位置中进行绘图,点(0,0)指整个窗口的左上角。其构造函数调用GetWindowDC,析构函数调用ReleaseDC函数。
(3)CMetaFileDC封装了在一个Windows图元文件中绘图的方法。图元文件是一系列与设备无关的图片的集合,由于它对图像的保存比像素更精确,因而往往在要求较高的场合下使用,例如:AutoCAD的图像保存等。目前的Windows已使用增强格式(enhanced-format)的32位图元文件来进行操作。
2、 图形设备接口
Windows为设备环境提供了各种各样的绘图工具,例如:画笔、画刷、字体等。MFC封装了这些工具,并提供相应的类来作为应用程序的图形设备接口(GDI,Graphics Device Interface),这些类有一个共同的抽象基类CGdiObject,如下所示:
类 名 说 明
CBitmap “位图”是一种位矩阵,每一个显示像素都对应于其中的一个或多个位,用户可以利用位图来表示图象,也可以利用它来创建画刷
CBrush “画刷”定义了一种位图形式的像素,利用它可对区域内部填充颜色或样式
CFont “字体”是一种具有某种风格和尺寸的所有字符的完整集合,它常常
被当做资源存于磁盘中,其中有一些还依赖于某种设备
CPalette “调色板”是一种颜色映射接口,它允许应用程序在不干扰其它应用
程序的前提下,充分利用输出设备的颜色描绘能力
CPen “画笔”是一种用于画线及绘制有形边框的工具,用户可以指定它的
颜色及宽度,并且可以指定它实线、点线或虚线等
CRgn “区域”是由多边形、椭圆或二者组合形成的一种范围,可以利用它来进行填充、裁剪以及鼠标点中测试等
2.1、使用GDI对象
选择GDI对象进行绘图时,一般要遵循下列步骤:
(1)定义一个GDI对象(如CPen、CBrush对象),然后用相应的函数(如CreatePen、CreateSolidBrush)创建此GDI对象。但要注意;有些GDI派生类的构造函数允许用户提供足够的信息,从而一步即可完成对象的创建任务,这些类有CPen、CBrush
(2)将构造的GDI对象选入当前设备坏境中,但不要忘记原来的GDI对象保存起来。
(3)绘图结束后,恢复当前设备环境中原来的GDI对象
如下列代码:
void CMyView::OnDraw(CDC *pDC)
{ CPen penBlack;//定义一个画笔变量
penBlack.CreatePen(PS_SOLID,2,rgb(0,0,0);//创建画笔
CPen *pOldPen=pDC->SelectObject(&penBlack);//将此画笔选入当前设备环境并
//保存原来的画笔
//用此画笔绘图
pDC->MoveTo(…);
pDC->LineTo(…);
//其他绘图函数
pDC->SelectObject(pOldPen);//恢复设备环境中原来的画笔
}
2.2、库存的GDI对象
除了自定义的GDI对象外,Windows还包含了一些预定义的库存GDI对象。由于它们是Windows系统的一部分,因此用户用不着删除它们。CDC的成员函数
SelectStockObject可以把一个库存对象选入当前设备环境中,并返回原先被选中的对象指针,同时使原先被选中的对象从设备环境中分离出来。如下代码:
void CMyView::OnDraw(CDC *pDC)
{
CPen newPen(PS_SOLID,2,RGB(0,0,0))
pDC->SelectObject(&newPen);
pDC->MoveTo(…);
pDC->LineTo(…);
… //其它绘图函数
pDC->SelectStockObject(BLACK_PEN);//newPen被分离出来
}
SelectStockObject函数可选用的库存GDI对象类型可以是下列值之一:
BLACK_BRUSH 黑色画刷
DKGRAY_BRUSH 深灰色画刷
GRAY_BRUSH 灰色画刷
HOLLOW_BRUSH 中空画刷
LTGRAY_BRUSH 淡灰色画刷
NULL_BRUSH 空画刷
WHITE_BRUSH 白色画刷
BLACK_PEN 黑色画笔
NULL_PEN 空画笔
WHITE_PEN 白色画笔
DEVICE_DEFAULT_FONT 设备默认字体
SYSTEM_FONT 系统字体
图形的绘制通常需要先创建画笔和画刷,然后调用相应的绘图函数。
3、 画笔
画笔是Windows应用程序中用于绘制各种直线和曲线的图形工具。它可分为修饰画笔和几何画笔两种类型。在这2种类型中,几何画笔的定义最复杂,它不但有修饰画笔的属性,而且还和画笔的样式、阴影线类型有关,通常用在对绘图有较高要求的场合。而修饰画笔只有简单的几种属性,通常用在简单的直线和曲线等场合。
一个修饰画笔通常具有宽度、风格和颜色3种属性。画笔的宽度用于确定所画的线条宽度,它是用设备单位表示的。默认的画笔宽度是一个像素单位。画笔的颜色确定了所画的线条颜色。画笔的风格确定了所绘图形的线型,它通常有实线、虚线、点线、点划线、双点划线、不可见线和内框线等7种风格。这些风格在Windows中都是以PS_为前缀的预定义的标识。以下为修饰画笔的风格:
PS_SOLID 实线
PS_DASH虚线
PS_DOT点线
PS_DASHDOT 点画线
PS_DASHDOTDOT双点画线
PS_NULL不可见线
PS_INSIDEFRAME 内框线
几何画笔这里不做介绍。
创建一个修饰画笔,可以使用CPen类的CreatePen函数,其原形如下:
BOOL CreatePen(int nPenStyle,int nWidth,COLORREF crColor);
参数分别表示画笔的:风格 宽度 颜色
此外,还有一个CrearePenIndirect函数也是用于创建画笔对象,它的作用与CreatePen函数是完全一样的,只是画笔的3个属性不是直接出现在函数参数中,而是通过一个LOGPEN结构间接地给出。
BOOL CreatePenIndirect(LPLOGPEN lpLogPen);
此函数用由LOGPEN结构指针指定的相关参数创建画笔。LOGPEN结构如下。
typedef struct tagLOGPEN
{
/* lgpn*/
UINT lopnStyle;//画笔风格,
POINT lopnWidth;//POINT结构的y不起作用,而用x表示画笔宽度
COLORREF lopnColor;//画笔颜色
}LOGPEN;
值得注意的是:
(1)当修饰画笔的宽度大于1个像素时,画笔的风格只能取PS_NULL、
PS_SOLID或PS_INSIDEFRAME定义,为其他风格不会起作用。
(2)画笔的创建工作也可在画笔的构造函数进行,它具有下列原形:
CPen(int nPenStyle,int nWidth,COLORREF crColor);
4、 画刷
画刷用于指定充填的特性,许多窗口、控件以及其它区域都需要用画刷进行充填绘制,它比画笔的内容更加丰富。画刷的属性通常包括填充色、填充图案和填充样式3种,画刷的填充色和画笔颜色一样,都是使用COLORREF颜色类型,画刷的填充图案通常是用户定义的8*8位图,而填充样式往往是CDC内部定义的一些特性,它们是以HS_为前缀的标识,如书308页图7.3所示。
CBrush类根据画刷属性提供了相应的创建函数,例如创建填充色画刷和填充样式画刷的函数为CreateSolidBrush和CreateHatchBrush,它们的原型如下:
BOOL CreateSolidBrush(COLORREF crColor);//创建填充色画刷
BOOL CreateHatchBrush(int nlndex,COLORREF crColor);//创建填充样式画刷
其中:nIndex用于指定画刷的内部填充样式,而crColor表示画刷的填充色。
与画笔相类似,也有一个LOGBRUSH逻辑结构用于画刷属性的定义,并通过CBrush的成员函数CreateBrushIndirect来创建,其原型如下:
BOOL CreateBrushIndirect(const LOGBRUSH *lpLogBrush);
其中:LOGBRUSH逻辑结构如下定义:
typedef struct tagLOGBRUSH
{ //lb
UINT lbStyle; //风格
COLORREF lbColor;//填充色
LONG lbHatch;//填充样式
}LOGBRUSH;
另外,还需注意:
(1)画刷的创建工作也可在其构造函数中进行,它具有下列原型:
CBrush(COLORREF crColor);
CBrush(int nIndex,COLORREF crColor);
CBrush(CBitmap *pBitmap);
(2)画刷也可用位图来指定其填充图案,但该位图应该是8*8像素,若位图太大,Windows则只使用其左上角的8*8的像素。
(3)画刷仅对绘图函数Chord、Ellipse、FillRect、FrameRect、InvertRect、Pie、Polygon、PolyPolygon、Rectangle、RoundRect有效。
例:绘制一条由点连起的曲线(简单图形)
1、 建一个单文档的应用程序
2、在Viwe.cpp的OnDraw(CDC *pDC)函数里加如下代码:
int data[20]={19,21,32,40,41,39,42,35,33,23,21,20,24,
11,9,19,22,32,40,42};
CRect rc;
GetClientRect(rc);
rc.DeflateRect(50,50);
int gridXnums=10,gridYnums=8;
int dx=rc.Width()/gridXnums;
int dy=rc.Height()/gridYnums;
CRect gridRect(rc.left,rc.top,rc.left+
dx *gridXnums,rc.top+dy *gridYnums);
CPen gridPen(0,0,RGB(0,100,200));
CPen *oldPen=pDC->SelectObject(&gridPen);
for(int i=0;i<=gridXnums;i++)
{
pDC->MoveTo(gridRect.left+i *dx,gridRect.bottom);
pDC->LineTo(gridRect.left+i *dx,gridRect.top);
}
for(int j=0;j<=gridYnums;j++)
{
pDC->MoveTo(gridRect.left,gridRect.top+j *dy);
pDC->LineTo(gridRect.right,gridRect.top+j *dy);
}
pDC->SelectObject(oldPen);
gridPen.Detach();
gridPen.CreatePen(0,0,RGB(0,0,200));
pDC->SelectObject(&gridPen);
CBrush gridBrush(RGB(255,0,0));
CBrush *oldBrush=pDC->SelectObject(&gridBrush);
POINT ptRect[4]={{-3,-3},{-3,3},{3,3},{3,-3}},ptDraw[4];
int deta;
POINT pt[256];
int nCount=20;
deta=gridRect.Width()/nCount;
for(i=0;iPolygon(ptDraw,4);
}
pDC->Polyline(pt,nCount);
pDC->SelectObject(oldPen);
pDC->SelectObject(oldBrush);
(待完善)