创建字体
在应用可以使用非默认字体之前,该字体必须被创建并被选进设备环境里。在新字体被选进DC后,在DC里绘制的任何文本都使用这个新字体。
在Windows CE中创建字体的方法如下:
HFONT CreateFontIndirect (const LOGFONT *lplf);
该函数接受一个指向LOGFONT结构的指针,该结构必须使用您需要的字体描述来填充。
typedef struct tagLOGFONT {
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;
lfHeight 规定字体在设备单位下的高度。如果该域为0,字体管理器返回使用的字体系中默认字体尺寸。对于大多数应用程序来说,您需要创建一个特殊尺寸的字体。下面的公式用于给lfHeight转换磅值:
lfHeight = –1 * (PointSize * GetDeviceCaps (hdc, LOGPIXELSY) / 72);
这里传给GetDeviceCaps的LOGPIXELSY告诉函数返回垂直方向上每英寸的逻辑像素数。72表示每英寸的磅值(磅是用于排版的计算单位)
lfWidth规定了平均字符宽度。因为字体的高度比宽度更重要,所以大多数程序都把这个值设为0。表示让字体管理器根据字体高度计算出合适的宽度。lfEscapement 和lfOrientation 规定了字符基线同X坐标轴之间以十分之一度为单位的旋转角度。lfWeight规定了从0到1000范围内的字体粗细程度,其中400是标准字体,700是加重字体。接下来的三个域规定了字体是否是斜体、下划线或者删除线。
lpCharSet规定了您选择的字符集。该域对于软件的国际版本是很重要的,因为国际版本一般都要求特定的语言字符集合。lfOutPrecision 规定Windows匹配您请求的字体的精确程度。在众多可以使用的标志当中,OUT_TT_ONLY_PRECIS标志规定创建的字体必须是TrueType字体。
lfClipPrecision规定Windows如何裁剪超出显示区域的字符。
lfQuality 可以设置为以下几种:
DEFAULT_QUALITY 默认系统质量
DRAFT_QUALITY 牺牲质量换取速度
CLEARTYPE_QUALITY 用ClearType技术绘制文本
CLEARTYPE_COMPAT_QUALITY 用ClearType技术绘制文本。对非ClearType字体使用同样的空间。
ClearType是一种为字体提供更清晰的外观的文本显示技术,该技术独立寻址红、绿、蓝LCD,它们在彩色LCD显示器上构成一个像素。根据系统的不同,有的可能不支持ClearType,有的可能对系统里的所有字体都支持。对于支持ClearType但不完全支持的系统来说,使用CLEARTYPE_QUALITY 或CLEARTYPE_COMPAT_QUALITY 可以创建用ClearType绘制的字体。因为ClearType并不改进所有字体的外观,所以您应该测试一下,看ClearType是否对您选择的字体有所改进。
lfPitchAndFamily规定了您选择的字体的字系。当您请求诸如Swiss字系--一种没有衬线的专业字体--时,使用该域很方便。再例如选择Roman字系--一种带衬线的专业字体--时,也很方便,但您要注意不要针对特定的字体。您也可以用该域来规定均衡或等宽字体,并让Windows来决定使用哪种字体来匹配传给LOGFONT结构的特定特性。最后,lfFaceName域用来指明具体字体的字体名称。当用一个填充后的LOGFONT结构调用CreateFontIndirect时,Windows根据提供的特性,创建一个最匹配的逻辑字体。为了使用该字体,需要做的最后一步是选择该字体到一个设备环境里。
选择字体到设备环境
用SelectObject 函数将字体选进DC里,函数如下所示:
HGDIOBJ SelectObject (HDC hdc, HGDIOBJ hgdiobj);
该函数不仅仅用于设置默认字体,还用在很多地方;正如您很快就会看到的,可以用该函数来选择其它GDI对象。该函数返回先前被选择的对象(在本例中返回的是先前选择的字体),应该保存该返回值以便当您用完新的字体后可以把先前的选择回DC里。代码行如下所示:
hOldFont = (HFONT)SelectObject (hdc, hFont);
当逻辑字体被选择时,系统从可使用的字体中选择最匹配的逻辑字体。对没有TrueType字体的设备,匹配的字体同指定的参数相比有一定数量的差异。因此,不要想当然的认为您请求了一个特殊字体,返回的就是准确匹配的字体。例如,您要求的字体高度可能和选进设备环境的字体高度是不一样的。
查询字体特性
为了确定选进设备环境的字体的特性,调用GetTextMetrics 函数来返回字体特性,函数原型如下:
BOOL GetTextMetrics (HDC hdc, LPTEXTMETRIC lptm);
TEXTMETRIC结构带有返回信息,该结构定义如下:
typedef struct tagTEXTMETRIC {
LONG tmHeight;
LONG tmAscent;
LONG tmDescent;
LONG tmInternalLeading;
LONG tmExternalLeading;
LONG tmAveCharWidth;
LONG tmMaxCharWidth;
LONG tmWeight;
LONG tmOverhang;
LONG tmDigitizedAspectX;
LONG tmDigitizedAspectY;
char tmFirstChar;
char tmLastChar;
char tmDefaultChar;
char tmBreakChar;
BYTE tmItalic;
BYTE tmUnderlined;
BYTE tmStruckOut;
BYTE tmPitchAndFamily;
BYTE tmCharSet;
} TEXTMETRIC;
TEXTMETRIC结构包含了LOGFONT结构中的很多域,但此时TEXTMETRIC的值是选进设备变量的字体的特性。图2-3显示了一些域同实际字符之间的关系。
图2-3(图略):TEXTMETRIC结构及其与字体的关系。
除了可以判断您是否真的获得了您需要的字体外,GetTextmetrics函数调用还有另外一个有价值的用途--确定字体高度。回忆一下TextDemo程序,行的高度是通过调用DrawText函数计算出来的。虽然那种方法很方便,但它有点慢。您可以使用TEXTMETRIC数据,以更加直接的方法来计算高度。将表示字符高度的tmHeight域与tmExternalLeading域--表示一行底部像素到下一行顶部像素之间的间距--相加,您就可以获得两行文本基线的间距了。
虽然GetTextMetrics对确定字符高度来说是很好用的,但它只提供了字体的平均宽度和最大宽度。如果需要TrueType的更多细节,可以使用函数GetCharABCWidths,函数原型如下:
BOOL GetCharABCWidths (HDC hdc, UINT uFirstChar, UINT uLastChar, LPABC lpabc);
GetCharABCWidths返回由uFirstChar 和 uLastChar 参数所确定的一系列字符的ABC宽度。该函数检查hdc参数指定的DC里的字体。ABC结构如下:
typedef struct _ABC {
int abcA;
UINT abcB;
int abcC;
} ABC;
abcA为在放置字符轮廓前的空白间距,abcB为字符轮廓本身的间距,abcC为字符轮廓右方的空白间距。abcA和abcC都可以是负值,用来指示缩进或者凸起。
要获得点阵字体(bitmap fonts)的宽度,可以使用GetCharWidth32函数。对指定字符范围内的每个字符,该函数返回一个字符宽度数组。