您的位置:首页 > 其它

在SDK中使用TextOut进行文字输出

2008-10-16 21:36 302 查看
=============《Windows 程序设计 第五版》读书笔记 || 第四章 输出文字 =============

这看似是一个很简单的问题,不就是进行文字的输出么,C语言里的printf ,C++里的count,都很简单的,不过这在SDK中却是件难事儿。在SDK中输出一段文字,不仅需要设置文字的颜色、字体、字体高度、字体宽度,还得设置文字的背景颜色,相比于C/C++中的文字输出,要复杂许多。要弄清在SDK中,文字是怎么显示在窗体上的,还得了解一下Windows中文字的一些细节问题。

一、系统字体

如何设置文字的颜色,在这一章中没有作介绍,默认情况下,输出文字的背景颜色是使用WNDCLASS结构中hbrBackground字段的设置,比如在写WNDCLASS窗口类时,将hbrBackground设置为灰色,那么TextOut默认输出的文字背景就是灰色的(注释:好像搞错了,即便hbrBackground为其它颜色,TextOut默认输出文字的背景颜色仍然是白色)。

先说说这个系统字体吧!

系统字体是一种「点阵字体」,也就是每个字都是用点组合而成,所谓三点成一线,这点阵字体就是这么回事儿。TextOut默认输出的是系统字体,也就是点阵字体,这个点阵字体,在“控制面板”的“字体”窗口中也能找到,我在Windows记事本中设置了名为“Courier” 的点阵字体(如图1),有点儿难看,还有“Courier New”也是一个点阵字体,字体效果跟“Courier”一个样。书上说在以前的Windows版本中,系统字体是一种等宽字体,看这点阵字体的效果,好像就是一种等宽字体。



图1

二、字符大小

弄清字符大小对我来说算是一个难点,字符大小包括字符的宽度和高度,而字符高度由五个部分组成,这咱先不说,先说说存放字符信息的结构体TEXTMETRIC。呃。。。好像不对,要弄清TEXTMETRIC结构体中的各个字段的作用,还得先说说组成字符高度的那五个部分。用图说话,先看看书中的这张图(如图2)。


图2

刚开始看这个图的时候有一些晕乎,可能是被图书的英文吓的吧!不过换了一种方法后,就恍然大悟了。咱把这一个字符看作是书中的一个页面,一个书页有页眉/正文和页脚,而tminternalLeading就是书页的页眉,不过这个tminternalLeading是放字母声调之类的东西,比如拼音中的一声调,二声调,三声调和四声调。tmAscent是书页的页眉+正文部分,最后tmDescent是书页的页脚,页眉+正文+页脚等于书页的高度,那么tmAscent+tmDescent就是字符的高度了,即tmHeight。

一个字符除了这五个组成部分之外,还有一个tmExternalLeading,书上说它是字体设计者建议加在横向字符之间的空间大小,这句话按字面来理解,那就是说tmExternalLeading是设置字符间距咯,不过根据实践证明,这是设置字符行间距的,就是上一行和下一行之间的距离,而一个字符的高度真实高度是tmHeight+tmExternalLeading,即字符本身的高度加上行间距,tmExternalLeading默认值为0。

说了字符的高度,还得说说字符的宽度,这相对简单些,我们所需要知道的就是字符的平均宽度(tmAveCharWidth)和最大宽度(tmMaxCharWidth),我不知道为什么会有字符的平均宽度,但对于等宽字符,字符的平均宽度和最大宽度是相同的。

先对上面的这部分内容作个总结,主要说了点阵字体/等宽字体和变宽字体,现在我们用的好像是TrueType 字体,是一种变宽字体,估计在第十七章中会作详细介绍。

好了,弄清楚的字体高度的组成部分,接下来就来说说TEXTMETRIC结构体,先看看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;

TCHAR tmFirstChar;

TCHAR tmLastChar;

TCHAR tmDefaultChar;

TCHAR tmBreakChar;

BYTE tmItalic;

BYTE tmUnderlined;

BYTE tmStruckOut;

BYTE tmPitchAndFamily;

BYTE tmCharSet;

} TEXTMETRIC, *PTEXTMETRIC;

对于这个结构中的这些字段,我们只需要知道前面七个是啥意思就行了,而这七个字段在前面都已经解释清楚了。现在我们就可以使用GetTextMetrics函数来将字符的这些信息存放到TEXTMETRIC结构体中了:

TEXTMETRIC tm; //定义一个TEXTMETRIC结构体

GetTextMetrics(hdc, &tm);

通过断点调试,可以看到tm结构体中各个字段的值(如图3)。


图3

下面来个实例练习一下:

hdc = GetDC (hwnd) ; //获得一个设备内容句柄

GetTextMetrics (hdc, tm) ; //获得字体信息存入tm结构体

cxChar = tm.tmAveCharWidth ; //字符平均宽度

cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ; //这个应该是设置变宽字体的平均宽度

cyChar = tm.tmHeight + tm.tmExternalLeading ; //字符高度

ReleaseDC (hwnd, hdc) ;

在对字符的高度和宽度进行设置后,就可以使用TextOut来输出文字了。最后准备来个完整的实例,不过还得先看看TextOut函数的几个参数,其实也挺简单的:

TextOut (hdc, x, y, psText, iLength) ;

算了,这几个参数太简单,就不解释了,来个实例代码吧,看看如何用TextOut输出多行文字。

static int cyChar; //TextOut中参数y的值

TEXTMETRIC tm; //字体信息的结构体

PAINTSTRUCT ps; //重绘区域

case WM_CREATE:

hdc = GetDC (hwnd) ;

GetTextMetrics (hdc, tm) ;

cxChar = tm.tmAveCharWidth ;

cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;

cyChar = tm.tmHeight + tm.tmExternalLeading + 10 ;

ReleaseDC (hwnd, hdc) ;

return 0;

case WM_PAINT:

hdc = BeginPaint (hwnd, &ps) ;

TextOut(hdc, 0, 0, "这是第一行文字", lstrlen("这是第一行文字"));

TextOut(hdc, 0, cyChar,

"这是第二行文字", lstrlen("这是第二行文字"));

EndPaint (hwnd, &ps) ;

return 0;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐