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

=============《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结构体中的各个字段:

  1. typedef struct tagTEXTMETRIC { 
  2.   LONG tmHeight; 
  3.   LONG tmAscent; 
  4.   LONG tmDescent; 
  5.   LONG tmInternalLeading; 
  6.   LONG tmExternalLeading; 
  7.   LONG tmAveCharWidth; 
  8.   LONG tmMaxCharWidth; 
  9.   LONG tmWeight; 
  10.   LONG tmOverhang; 
  11.   LONG tmDigitizedAspectX; 
  12.   LONG tmDigitizedAspectY; 
  13.   TCHAR tmFirstChar; 
  14.   TCHAR tmLastChar; 
  15.   TCHAR tmDefaultChar; 
  16.   TCHAR tmBreakChar; 
  17.   BYTE tmItalic; 
  18.   BYTE tmUnderlined; 
  19.   BYTE tmStruckOut; 
  20.   BYTE tmPitchAndFamily; 
  21.   BYTE tmCharSet; 
  22. } TEXTMETRIC, *PTEXTMETRIC; 

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

  1. TEXTMETRIC tm//定义一个TEXTMETRIC结构体
  2. GetTextMetrics(hdc, &tm);

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

 

 

图3

下面来个实例练习一下:

  1. hdc = GetDC (hwnd) ; //获得一个设备内容句柄
  2.         
  3. GetTextMetrics (hdc, tm) ; //获得字体信息存入tm结构体
  4. cxChar = tm.tmAveCharWidth ; //字符平均宽度
  5.         
  6. cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ; //这个应该是设置变宽字体的平均宽度
  7.         
  8. cyChar = tm.tmHeight + tm.tmExternalLeading ; //字符高度
  9.         
  10. ReleaseDC (hwnd, hdc) ;

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

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

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

  1. static int cyChar; //TextOut中参数y的值
  2. TEXTMETRIC tm//字体信息的结构体
  3. PAINTSTRUCT ps; //重绘区域
  4. case WM_CREATE:
  5.         hdc = GetDC (hwnd) ;
  6.         GetTextMetrics (hdc, tm) ;
  7.         cxChar = tm.tmAveCharWidth ;
  8.         cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;
  9.         cyChar = tm.tmHeight + tm.tmExternalLeading + 10 ;
  10.         ReleaseDC (hwnd, hdc) ;
  11.         return 0;
  12.     case WM_PAINT:
  13.         hdc = BeginPaint (hwnd, &ps) ;
  14.         TextOut(hdc, 0, 0, "这是第一行文字", lstrlen("这是第一行文字"));
  15.         
  16.         TextOut(hdc, 0, cyChar,
  17.             "这是第二行文字", lstrlen("这是第二行文字"));
  18.         EndPaint (hwnd, &ps) ;
  19.         return 0;

 

 

 

posted @ 2008-10-16 21:36  冷寒生  阅读(2682)  评论(0编辑  收藏  举报
IT知识库