前面的程序只能画基本的图形,我们不能改变线条的颜色,线条的大小,不能填充颜色,也不能改变字体,显示一张位图等。要实现这些功能,我们就要使用GDI对象。不过,GDI对象是要通过DC才能发生作用的。要使用这些GDI对象,必须使用SelectObject函数将其选入DC中,如::SelectObject(hdc, hPen);
当然,使用之前,这些GDI对象必须存在,可以通过如下Win32函数来创建这些对象:
或者,通过Win32函数HGDIOBJ GetStockObject(int fnObject)来获取系统预先定义好的如下备用对象:
fnObject参数 含义
这里需再次强调一下:GDI对象要选入Windows 设备描述表后才能使用;用毕,要恢复设备描述表的原GDI对象,并删除该GDI对象。
一般按如下步骤使用GDI对象:
a、创建或得到一个GDI对象
b、使用dc.SelectObject函数把GDI对象选入DC
c、使用DC进行绘图或文字输出
d、恢复DC原来的GDI对象并删除刚新创建的GDI对象。
综合DC和GDI对象的使用步骤,则绘图的完整步骤为:
1. 获取或者创建一个DC
2. 获取或者创建一个GDI对象(Pen, Brush等)
3. 使用dc.SelectObject函数把GDI对象选入DC
4. 使用DC进行绘图或文字输出
5. 恢复DC原来的GDI对象并删除刚新创建的GDI对象,如pen.DeleteObject()
6. 释放或删除设备描述表DC
其中,1和6,2和4是对应的。
MFC GDI对象
MFC用一些类封装了Windows GDI对象和相关函数,层次结构如图所示:
(1)画笔
画笔决定了线条的颜色、宽度和线型(实线、点线或点划线等)。Windows使用当前在设备描述表中已选择的画笔来画线。程序中可以选择Windows的予定义画笔,也可以选择自定义的画笔。
预定义画笔有三种:BLACK_PEN(黑色笔) 、WHITE_PEN(白色笔)和NULL_PEN(空笔),这些都在windows.h中已经定义好了,程序员可使用GetStockObject函数来选择其中的一种,系统缺省的画笔为黑色笔。Windows.h包含了HPEN的数据类型定义,使用该类型可以定义画笔句柄的变量。
仅靠系统提供的预定义画笔远远不能满足需求,应用程序可根据实际需要创建一种自定义的逻辑画笔。其步骤一般为:首先用CreatePen或CreatePenIndirect函数建立一支画笔,再调用SelectObject函数将其选入设备描述表,此后就可使用该画笔在选定的设备描述表中进行绘图操作。任何时候某一设备描述表只能有一支画笔被选入作为当前画笔,当一支画笔被选入时,原先已选入的画笔便不再有效。完成绘图操作后,可以通过调用DeleteObject来释放已建立的画笔。
* 函数CreatePen()
语法:HPEN CreatePen(int fnPenStyle,int nWidth,COLORREF clrref);
说明:该函数创建一个逻辑画笔。其中
fnPenStyle参数指定画笔的线型,该参数可取由windows.h定义的七个标识符之一,其含义为:
PS_SOLID 实线
PS_DASH 虚线
PS_DOT 点线
PS_DASHDOT 夹一点虚线
PS_DASHDOTDOT 夹二点虚线
PS_NULL 无
PS_INSIDEFRAME 线画在所有构件框架内
nWidth参数是用逻辑单位表示的画笔的宽度;
clrref参数是一个COLORREF类型的颜色值,指定画笔的颜色,可用宏指令RGB构造这个值,如:clrref=RGB(byRed,byGreen,byBlue);
在使用CreatPen函数时,要检查其返回值,确保它是一个有效的句柄。
下面给出一段程序,说明建立、选择和释放画笔的一般方法,假定程序要用一支宽度为3的黑色作图,则程序如下:
CPen *p_Pen;
CDC dc;
p_Pen->CreatePen(PS_SOLD,3,RGB(0,0,0));
if(p_Pen)
{
dc.SelectObject(p_Pen);
//… //这里进行绘图操作
}
Delete p_Pen; //删除hPen画笔,释放空间
* 函数CreatePenIndirect()
语法:HPEN CreatePenIndirect(LOGPEN FAR* lpLogPen);
说明:该函数用lpLogPen所指的LOGPEN结构中的信息创建一个逻辑画笔。
LOGPEN的结构如下:
typedef struct tagLOGPEN(
WORD lopnStyle;
POINT lopnWidth;
COLORREF lopnColor;
) LOGPEN;
其中lopnStyle指定画笔线型,该参数可取下列值之一:
PS_SOLID 0
PS_DASH 1
PS_DOT 2
PS_DASHDOT 3
PS_DASHDOTDOT 4
PS_NULL 5
PS_INSIDEFRAME 6
nWidth参数是用逻辑单位表示的画笔的宽度
clrref参数是一个COLORREF类型的颜色值,指定画笔的颜色,可用宏指令RGB构造这个值。
(2)刷子
当我们在绘制一些区域图形时,其内部往往需要以某种图案进行填充,这就需要选定"刷子"作为绘图工具。Windows系统不仅为用户提供了预定义刷子,而且还允许应用程序自定义刷子。
Windows系统中预定义的刷子有如下七种:
BLACK_BRUSH 黑色刷子
DKGRAY_BRUSH 深灰色刷子
GRAY_BRUSH 灰色刷子
HOLLOW_BRUSH 中空刷子,画边界而不填充
LTGRAY_BRUSH 浅灰色刷子
NULL_BRUSH 空刷子
WHITE_BRUSH 白色刷子
应用程序可以调用GetStockObject函数选用其中一个,系统缺省的刷子是白色刷子。Window.h包含了HBRUSH数据类型的定义,使用该类型就可定义刷子句柄的变量。
仅靠这七种刷子往往不能满足要求,应用程序通过调用如下几种函数创建逻辑刷子,这些函数返回值均为刷子句柄。
* 函数CreateHatchBrush()
语法:HBRUSH CreateHatchBrush(int fnStyle, COLORREF clrref);
说明: 该创建一个带阴影的逻辑刷子。
FnStyle指定的阴影格式如下:
HS_BDLAGONAL 45度向上斜线组成的阴影图案(自左到右)
HS_CROSS 水平和垂直交叉组成的阴影图案
HS_DIAGCROSS 45度斜线交叉组成的阴影图案
HS_FDIAGONAL 45度向下斜线组成的阴影图案(自左到右)
HS_HORZONA 水平线组成的阴影图案
HS_VERTICAL 垂直线组成的阴影图案
Clrref是具有COLORREF类型定义的刷子颜色值,可用宏指令RGB构造这个值。
* 函数CreateSolidBrush()
语法:HBRUSH CreateSolidBrush(COLORREF clrre);
说明:该函数创建的是一种实心颜色的逻辑刷子。clrre含义同上。
同样,使用创建刷子的函数时,要检查其返回,确保它是一个有效的句柄。
一旦创建了绘图工具之后,可以SelectObject函数把它选择到显示缓冲区里。
在使用显示缓冲区之前,并不一定非要创建和选择绘图工具,Windows为每个显示缓冲区提供默认的绘图工具。例如:黑色笔,白色刷子和系统字体。
DeleteObject函数用来删除不再需要的绘图工具,但不能删除一个已选进显示缓冲区的绘图工具,而是应该使用SelectObject函数恢复原有的绘图工具,然后再删除需要删除的工具。
(3) 填 充 图 形
绘制一些需要以某种图案进行填充的区域图形时,需要选定"刷子"作为绘图工具。Windows系统中预定义的刷子有七种,应用程序可以调用GetStockObject函数选用其中一个,系统缺省的刷子是白色刷子。
当靠这七种刷子不能满足要求时,应用程序通过调用Windows函数创建逻辑刷子,这些函数返回值均为刷子句柄。
(4) 文字与字体
Windows是使用定义好的与设备无关的字符集,Windows的"文本"字符也是图形,所以屏幕上所显示的用打印机或绘图仪等输出品的文本完全一样,做到"所见即所得"。
文本绘制函数有:
TextOut 以当前的字体写一字符串
DrawText 在一个特定矩形区中绘制某一格式的文本
ExtTextOut 在一个特定矩形区中,以当前字体写一字符串
GrayString 用灰色文本写一字符串
TabbedTextOut 写一带扩展字符的字符串
要输出文本就离不开字体。获取字体的相关信息可以使用函数:
BOOL GetTextMetrics( LPTEXTMETRIC lpMetrics )
结构TEXTMETRIC的定义如下所示:
typedef struct tagTEXTMETRIC { // tm
LONG tmHeight; //字符高度
LONG tmAscent; //字符上部高度(基线以上)
LONG tmDescent; //字符下部高度(基线以下)
LONG tmInternalLeading; //由tmHeight定义的字符高度的顶部空间数目
LONG tmExternalLeading; //加在两行之间的空间数目
LONG tmAveCharWidth; //平均字符宽度
LONG tmMaxCharWidth; //最宽字符的宽度
LONG tmWeight; //字体的粗细轻重程度
LONG tmOverhang; //加入某些拼接字体上的附加高度
LONG tmDigitizedAspectX; //字体设计所针对的设备水平方向
LONG tmDigitizedAspectY; //字体设计所针对的设备垂直方向
BCHAR tmFirstChar; //为字体定义的第一个字符
BCHAR tmLastChar; //为字体定义的最后一个字符
BCHAR tmDefaultChar; //字体中所没有字符的替代字符
BCHAR tmBreakChar; //用于拆字的字符
BYTE tmItalic; //字体为斜体时非零
BYTE tmUnderlined; //字体为下划线时非零
BYTE tmStruckOut; //字体被删去时非零
BYTE tmPitchAndFamily; //字体间距(低4位)和族(高4位)
BYTE tmCharSet; //字体的字符集
} TEXTMETRIC;
GDI字体族和字样
GDI字体族和字样表如下表所示:
字体族 字体族常量 字样说明
Dontcare FF_DONTCARE System 当不能提供字体信息或字体并不
重要时使用
Decorative FF_DECORATIVE Symbol 新奇字体
Modern FF_MODERN Courer,ModernIerminal 笔画大小固定的字体,但衬线可有可无
Roman FF_ROMAN Roman,TimeRoman 有衬线的、笔画大小可变的罗马字体
Script FF_SCRIPT Script 仿手写体
Swiss FF_SWISS Helvetical,System 无衬线的、笔画大小可变的字体
* CreateFontIndirect函数
语法: HFONT CreateFontIndirect(
CONST LOGFONT *lplf // pointer to logical font structure
);
说明:参数lplf是LOGFONT结构的指针。结构中含有逻辑字体的特征信息。该函数用lplf所指的LOGFONT结构中的信息创建一种逻辑字体。LOGFONT结构的定义如下:
typedef struct tagLOGFONT { // lf
LONG lfHeight; //字高度
LONG lfWidth; //字符平均宽度
LONG lfEscapement; //行与水平页角度
LONG lfOrientation; //基线与水平角度
LONG lfWeight; //笔划的粗细
BYTE lfItalic; //非零为斜体
BYTE lfUnderline; //非零为下划线
BYTE lfStrikeOut; //非零为中划线
BYTE lfCharSet; //指定字符集
BYTE lfOutPrecision; //输出精度
BYTE lfClipPrecision; //裁剪精度
BYTE lfQuality; //输出质量
BYTE lfPitchAndFamily; //字体的字距和族
TCHAR lfFaceName[LF_FACESIZE]; //含字体名的字符串
} LOGFONT;
* 函数SetTextAlign
大多数文本函数传递的参数表都要求有一个点坐标参数以定义写文本的参考点。当前文本对齐属性规定了字符串如何相对于所传递的坐标进行写。SetTextAlign函数用以设置当前文本对齐属性。
语法: UINT SetTextAlign(
HDC hdc, // handle to device context
UINT fMode // text-alignment flag
);
说明:该函数设置文本对齐方式。Hdc是参数描述表,fuAlign是文本对齐方式
* GetClientRect函数
语法: BOOL GetClientRect(
HWND hWnd, // handle to window
LPRECT lpRect // address of structure for client coordinates
);
说明: hWnd是与用户区域相关的窗口,lpRect是指向RECT结构的指针。