《Windows API每日一练》16.1 简单的文本输出

本节首先介绍Windows提供的几个文本输出函数、一些会影响文本输出的设备环境属性和如何使用备用字体。

本节必须掌握的知识点:

        文本输出函数

        文本的设备环境属性

        使用库存字体

16.1.1文本输出函数

       ■常见的文本输出函数

●TextOut 函数

函数调用:

TextOut(hdc,xStart,yStart,pString,iCount)

TextOut 函数用于在设备上下文(DC)中绘制文本的函数。它可以在指定的位置上绘制单行文本。

BOOL TextOut(

  HDC     hdc,       // 设备上下文句柄

  int     x,           // 起始位置的横坐标

  int     y,            // 起始位置的纵坐标

  LPCTSTR lpString,     // 要绘制的文本字符串

  int     c           // 要绘制的字符数,-1 表示绘制整个以 null 终止的字符串

);

返回值:如果函数成功绘制文本,则返回非零值;如果失败,则返回零。

xStart和yStart使用的是逻辑坐标,TextOut并不以NULL来做字符串的结束,需指定字符的个数iCount的值。

使用 TextOut 函数绘制文本的示例代码如下:

HDC hdc;  // 假设已有设备上下文句柄

// 设置文本属性(可选)

SetTextColor(hdc, RGB(255, 0, 0));  // 设置文本颜色

SetBkMode(hdc, TRANSPARENT);  // 设置背景透明

int x = 100;  // 起始位置的横坐标

int y = 100;  // 起始位置的纵坐标

LPCTSTR text = _T("Hello, World!");  // 要绘制的文本

TextOut(hdc, x, y, text, -1);  // 绘制文本

在上述示例中,我们首先设置了文本的属性,例如颜色和背景透明度。然后,我们指定了文本绘制的位置和要绘制的文本内容,并调用 TextOut 函数进行绘制。

●SetTextAlign函数

SetTextAlign 函数用于设置文本对齐方式的函数。它可以控制文本在绘制时相对于指定点的对齐方式。

以下是 SetTextAlign 函数的语法:

UINT SetTextAlign(

  HDC hdc,          //设备上下文(DC)的句柄

  UINT fMode      //指定文本对齐方式的标志

);

返回值:

函数调用成功时,返回以前的文本对齐方式的标志。

函数调用失败时,返回 GDI_ERROR。

SetTextAlign函数会改变起始位置xStart和yStart的含义。

SetTextAlign

坐标值的含义

TA_LEFT

xStart:第一个字符的左侧坐标

TA_RIGHT

xStart:最后一个字符的右侧坐标

TA_CENTER

xStart:字符串正中间点的坐标

TA_TOP

yStart:所有字符的最高点,即所有字符在yStart的位置之下

TA_BOTTOM

yStart:所有字符都在yStart位置之上

TA_BASELINE

yStart:表示字符串在基线位置,即小写字母q或y下伸部分在基线之下。

TA_UPDATECP

1、忽略xStart和yStart,而是由如MoveToEx或LineTo等一些会改变当前坐标的函数指定的当前值。CP==Current Position?

2、此时TextOut函数也会改变坐标当前值,对于TA_LEFT,新坐标值在字符串结尾位置;对于TA_RIGHT,当前坐标值在新字符串开始位置;对于TA_CENTER,则仍在中间位置,不会改变。

●TabbedTextOut函数

TabbedTextOut 函数用于在设备上下文(DC)中绘制具有制表位对齐的文本的函数。它允许在文本中使用制表符并指定每个制表位的宽度,从而实现对齐的效果。

以下是 TabbedTextOut 函数的语法:

LONG TabbedTextOut(

  HDC        hdc,      // 设备上下文句柄

  int        x,            // 起始位置的横坐标

  int        y,            // 起始位置的纵坐标

  LPCTSTR    lpString,     // 要绘制的文本字符串

  int        cchString,      // 要绘制的字符数,-1 表示绘制整个以 null 终止的字符串

  int        nTabPositions,            // 制表位位置数组的元素数目

  const INT *lpnTabStopPositions,    // 指向整型数组的指针,包含制表位的位置信息

  int        nTabOrigin            // 制表位的起始位置(原点)

);

返回值:

如果函数成功绘制文本,则返回绘制文本的宽度(以像素为单位)。

如果函数失败,则返回 -1。

使用 TabbedTextOut 函数绘制具有制表位对齐的文本的示例代码如下:

HDC hdc;  // 假设已有设备上下文句柄

int x = 100;  // 起始位置的横坐标

int y = 100;  // 起始位置的纵坐标

LPCTSTR text = _T("Item1\tItem2\tItem3");  // 要绘制的文本,包含制表符

int nTabPositions = 3;  // 制表位位置数组的元素数目

// 制表位的位置信息,相对于 nTabOrigin 参数指定的原点

const INT tabPositions[] = {150, 250, 350}; 

int nTabOrigin = x;  // 制表位的起始位置(原点)

// 绘制具有制表位对齐的文本

TabbedTextOut(hdc, x, y, text, -1, nTabPositions, tabPositions, nTabOrigin); 

在上述示例中,我们指定了文本绘制的起始位置和要绘制的文本内容,其中文本中包含了制表符。我们还定义了制表位的位置数组和制表位的起始位置。然后,我们调用 TabbedTextOut 函数进行绘制。

【注意】TabbedTextOut 函数会根据制表位的位置信息对文本进行对齐。制表位的位置信息以像素为单位,并相对于制表位的起始位置进行指定。

函数调用:

TabbedTextOut(hdc,xStart,yStart,pString,iCount,iNumTabs,piTabStops,xTabOrigin);

  1.当遇到字符串包含制表符(‘\t’或0x09)时,会被转成空白位置和个数由xTabOrign和piTabStops数组里元素共同决定。

  2.iNumTabs指定制表符位置数组piTabStops中元素的个数。

  3.piTabStops :TabStop位置的数组(逻辑单位)。表示每个制表符开始的位置,元素必须按升序存储。注意,元素表示的是个相对位置,即相对于xTagOrigin的位置偏移,比如元素元素分别为{40,80,120,160,200}表示第1个tab从xTagOrgin+40像素的地方开始输出,第2个从xTagOrgin+80,第3个从xTagOrgin+120开始输出,依此类推…

  4.如果iNumTabs值为0,且piTabStops值为NULL则制表符将会按平均字符宽度的8倍来扩展。

5.iCount为-1时,遇\0自动结束。

 

总结

先依次输出字符串中的每个字符。遇到第n\t时,从piTabStops数组依次比较,进而找到这个tab的开始位置(找到的元素索引为i。注意,i不一定等于n),就可以确定tab的位置为xTabOrigin+piTabStops[i]。如果在数组中找不到,就按默认的字符宽度的8倍,去计算出这个tab的位置。若这个tab位置前的字符不够时,则用空格补全。

【实例分析1】——xTabStop==0时(本例用系统等宽字符,每个字符的平均宽度为8像素)

  TCHAR szText[] = TEXT("abcdfg\thi\tjklmnopqrstuvwxyz\th");//3个\t

  TabbedTextOut(hdc,0, 0, szText, -1,0, NULL,0);//默认Tab位置是字符宽度的8倍。

1.第1个Tab位为刻度8的位置(1*字符宽度的8倍),因刻度8之前只有6个字符,所以补充2个空格字符,然后输出hi两个字符,然后遇第2个Tab。

2.第2个Tab为16(2*字符宽度的8倍)的位置(即刻度16)处开始,由于字符数不够,得再补充6个空格字符。然后输出jklmnopqrstuvwxyz,此时再遇第3个字符。

3.第3个Tab开始的位置应为8的倍数,即8、16、24、32或40等,但因8、16、24、32处要么被字符占用,要么被以前的两个Tab占用,所以第3个Tab从40开始,然后输出h字符。

【实例分析2】——xTabStop==10*8时,即Tab位的原点在图中刻度10的位置。

  TCHAR szText[] = TEXT("abcdfg\thi\tjklmnopqrstuvwxyz\th");//3个\t

  TabbedTextOut(hdc,0, 0, szText, -1,0, NULL,10*8);//与上例唯一的不同,xTabStop

1.第1个Tab位为10+8的位置(其中10xTabStop,8与例一样),即上图中刻度的18开始,因刻度18之前只有6个字符,所以补充12个空格字符,然后输出hi两个字符,然后遇第2个Tab。

2.第2个Tab为(10+16)的位置(其中10为xTabStop)处开始,由于字符数不够得再补充6个空格字符。然后输出jklmnopqrstuvwxyz,此时再遇第3个字符。

3.第3个Tab开始的位置应为10+(8的倍数),即18、26、34、42或50等,但因8、18、26、34、42处要么被字符占用,要么被以前的两个Tab占用,所以第3个Tab从50开始,然后输出h字符。

【实例分析3】——讨论xTabStop==0时

TCHAR szText[] = TEXT("abcdfg\thi\tjklmnopqrstuvwxyz\th");//3个\t

//每个字符宽度是8,元素的含义表示Tab位在第5、6、15、30、45刻度处

  int iTabStops[] = { 5 * 8, 6 * 8, 15 * 8, 30 * 8,45 * 8 };

                                                                                 

  TabbedTextOut(hdc,0, 0, szText, -1,iLen, iTabStops,0);

1.第1个Tab位为15的位置(iTabStops的第3个元素),即上图中刻度的15开始,

因为第1个元素5,但其位置己被字符f占用,第2个元素6,其位置己被g占用,所以第1个Tab从第3个元素,即刻度15的位置开始,因前面只有6个字符,得补9个空格。

2.第2个Tab为刻度30的位置(即第4个元素)处开始,由于字符数不够得再补充13个空格字符。然后输出jklmnopqrstuvwxyz,此时再遇第3个字符。

3.第3个Tab本应从刻度45开始,但被占用,而此时数组中的元素己经用尽,所以按默认的8的倍数,即刻度48的位置开始,所以补1个0,然后输出h。

【实例分析4】——讨论xTabStop==10*8时,即xTabStop从10的刻度开始

TCHAR szText[] = TEXT("abcdfg\thi\tjklmnopqrstuvwxyz\th");//3个\t

//每个字符宽度是8

//元素的含义表示Tab位为xTabStop56153045这些偏移开始

  int iTabStops[] = { 5 * 8, 6 * 8, 15 * 8, 30 * 8, 45 * 8 };

                                                                                         

  TabbedTextOut(hdc,0, 0, szText, -1,iLen, iTabStops,10*8);

1.第1个Tab位为10+5的位置(其中10xTabStop,5iTabStops的第1个元素),即上图中刻度的15开始,因a到g只有6个字符,得补9个空格。然后输出hi

2.第2个Tab为10+15的位置(即第3个元素),而不是10+6(因为16位置被h占用),由于字符数不够得再补充8个空格字符。然后输出jklmnopqrstuvwxyz,此时再遇第3个字符。

3.第3个Tab本应从刻度10+45开始(因为10+30被占用),所以补13个0,然后输出h。

●ExtTextOut函数

ExtTextOut 函数用于在设备上下文(DC)中绘制文本的函数。它提供了更灵活的文本绘制选项,包括对齐方式、字符间距、字体和背景等的控制。

以下是 ExtTextOut 函数的语法:

BOOL ExtTextOut(

  HDC          hdc,    // 设备上下文句柄

  int          x,           // 起始位置的横坐标

  int          y,          // 起始位置的纵坐标

  UINT         fuOptions,// 绘制文本的选项

  const RECT   *lprc,        // 文本绘制的矩形区域

  LPCTSTR      lpString, // 要绘制的文本字符串

  UINT         cbCount,  // 要绘制的字符数,-1 表示绘制整个以 null 终止的字符串

  const INT    *lpDx       // 字符间距数组的指针

);

返回值:

如果函数成功绘制文本,则返回非零值。

如果函数失败,则返回零。

函数调用:

ExtTextOut(hdc,xStart,yStart,iOptions,&rect,pString,iCount,pxDistance);

  1.rect参数:当iOption==ETO_CLIPPED时,rect为剪切框;当iOption==ETO_OPAQUE时,rect为文本的背景框。这两个选项可以同时使用,也可以一个都不用。

2.pxDistance是指向一个整型数组,指定了字符串中相邻字符间的像素间距。如果为NULL,则为默认字符间距(可自由定制紧凑或宽松的字符间距)。

【注意】数组元素的个数要大于等于字符间隔的个数,即数组元素个数≥字符个数-1。

●DrawText函数

DrawText 函数用于在设备上下文(DC)中绘制格式化文本的函数。它提供了更高级的文本绘制功能,可以自动换行、对齐文本、计算文本绘制区域等。

以下是 DrawText 函数的语法:

int DrawText(

  HDC     hdc,       // 设备上下文句柄

  LPCTSTR lpchText,    // 要绘制的文本字符串

  int     nCount,      // 要绘制的字符数,-1 表示绘制整个以 null 终止的字符串

  LPRECT  lprc,       // 文本绘制的矩形区域

  UINT    uFormat    // 绘制文本的格式选项

);

返回值:

如果函数成功绘制文本,则返回绘制的文本内容的高度(以逻辑单位为准)。

如果函数失败,则返回零。

使用 DrawText 函数绘制文本的示例代码如下:

HDC hdc;  // 假设已有设备上下文句柄

LPCTSTR text = _T("Hello, World!");  // 要绘制的文本

RECT rect = {100, 100, 300, 200};  // 绘制文本的矩形区域

// 绘制文本

DrawText(hdc, text, -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK); 

在上述示例中,我们指定了要绘制的文本字符串和一个矩形区域,用于限制文本的绘制范围。然后,我们调用 DrawText 函数进行文本绘制,并通过 uFormat 参数指定了对齐和格式选项,如居中对齐、自动换行等。

函数调用:

DrawText(hdc,pString,iCount,&rect,iFormat);

  1.iCount为-1时,自动计算字符串长度。

2.iFormat

iForamt参数

含义

0

将以回车\r(或0x0D)及换行\n(或0x0A)分隔成多行文本。

DT_LEFT、

DT_RIGHT、

DT_CENTER

DT_VCENTER等

文本对齐标志

DT_SINGLELINE

单行文本,此时回车换行符无效。

DT_WORDBREAK

在临近边框的两个单词中换行

DT_EXTERNALLEADING

多行文本时,字符高度不含字体的外部间距,如果希望行间距包括这个外部间距,就要使用该标志。

DT_EXPANDTABS

默认两个制表位之间为八个字符宽度

●DrawTextEx函数

DrawTextEx 函数提供了比 DrawText 函数更高级的文本绘制功能,包括支持自定义字体、字间距、文本效果等。

以下是 DrawTextEx 函数的语法:

       int DrawTextEx(

  HDC         hdc,      // 设备上下文句柄

  LPTSTR       lpchText, // 要绘制的文本字符串

  int             cchText, // 要绘制的字符数,-1 表示绘制整个以 null 终止的字符串

  LPRECT     lprc,              // 文本绘制的矩形区域

  UINT       dwDTFormat,       // 绘制文本的格式选项

  LPDRAWTEXTPARAMS   lpDTParams      // 绘制文本的参数

);

返回值:

如果函数成功绘制文本,则返回绘制的文本内容的高度(以逻辑单位为准)。

如果函数失败,则返回零。

DRAWTEXTPARAMS 结构的定义如下:

typedef struct tagDRAWTEXTPARAMS {

  UINT cbSize;              // 结构的大小,用于指定结构的版本

  int  iTabLength;           // 定义制表符的宽度,以逻辑单位为准

  int  iLeftMargin;            // 定义文本的左边距,以逻辑单位为准

  int  iRightMargin;          // 定义文本的右边距,以逻辑单位为准

  UINT uiLengthDrawn;     // 返回实际绘制的文本字符数

} DRAWTEXTPARAMS, *LPDRAWTEXTPARAMS;

使用 DrawTextEx 函数绘制文本的示例代码如下:

HDC hdc;  // 假设已有设备上下文句柄

LPTSTR text = _T("Hello, World!");  // 要绘制的文本

RECT rect = {100, 100, 300, 200};  // 绘制文本的矩形区域

DRAWTEXTPARAMS dtParams;

dtParams.cbSize = sizeof(DRAWTEXTPARAMS);

dtParams.iTabLength = 4;

dtParams.iLeftMargin = 10;

dtParams.iRightMargin = 10;

// 绘制文本

DrawTextEx(hdc, text, -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK, &dtParams); 

16.1.2文本的设备环境属性

除了前面讨论过的SetTextAlign函数,还有一些其他的设备环境属性也会影响文本的 显示。使用默认的设备环境时,文字颜色设定为黑色。

设置文字颜色

●SetTextColor(hdc,rgbColor)或GetTextColor(hdc);//设置或获取文字颜色

设置背景模式

OPAQUE时表示不透明;TRANSPARENT(透明)

●SetBkMode(hdc,iMode);

   当为TRANSPARENT时,会用背景色给虚线或点划线中间的空白部分着色。

设置背景颜色

SetBkColor(hdc,rgbColor)

举例

    1.调用当前系统颜色设定文本颜色或背景

      SetTextColor(hdc,GetSysColor(COLOR_WINDOWTEXT));

      SetBkColor(hdc,GetSysColor(COLOR_WINDOW));

     2.响应WM_SYSCOLORCHANGE消息:——随系统颜色的更改自动更改文本和背景色。

      Case WM_SYSCOLORCHANGE:InvalidateRect(hwnd,NULL,TRUE);break;

设置字符间距

SetTextCharacterExtra(hdc,iExtra);——字符间距,默认为0,否则为iExtra

    1.iExtra为负数时,会被自动取绝对值,所以不能利用该函数让字符紧缩一点。

    2.iExtra是个逻辑单位。可以通过GetTextCharacterExtra取得当前字符间距。

16.1.3使用库存字体

调用 TextOut,TabbedTextOut,ExtTextOut,DrawText 或者 DrawTextEx 来输出文本时, Windows会使用在设备环境中的选定的字体。文字的字样(typeface)和字号(size)定义了一 种特定的字体(font)。使用不同字体显示文本的最简单方法是利用Windows提供的库存字体。

获取特定库存字体

hFont= GetStockObject(iFont);//iFont为系统预定义标识符

这里iFont可以在Window预定义的一些标识符中取值。然后可以使用以下函数指定某个设备环境来使用这个字体。

默认的设备环境中设定的字体被称为系统字体,你可以在调用GetStockObject函数时使用SYSTEM_FONT参数来获得系统字体。这是一个包含ANSI字符集的比例字体(proportional font)。在调用 GetStockObject 函数时使用 SYSTEM_FIXED_FONT可以获得一个指向等宽字体的控点,该等宽字体和Windows 3.0之前版本中的系统字体兼容。如果希望所有字符的宽度都相等,直接调用这个函数就可以了。

库存字体 OEM_FIXED_FONT,又称为终端字体(terminal font),是 Windows 在 MS-DOS 命令提示窗口中使用的字体。它含有的字符集是同IBM PC扩展字符集相兼容的。Windows 的窗口标题列、菜单和对话框的文本中使用的是DEFAULT_GUI_FONT库存字体。

虽然GetStockObject函数提供了使用不同字体的最简便的方式,但它不能充分利用 Windows提供的字体。接下来,我们来看如何指定文本的字样和字号。

选入设备环境

SelectObject(hdc,hFont);

字体作为一个GDI对象存在的,获取特定字体之后,需要调用SelectObject函数将其选入到设备环境中。或者可以把这两步合并,使用以下一条语句来实现:

SelectObject (hdc, GetStockObject (iFont));

获取当前字体信息

利用GetTextMetrics函数获取当前字体信息。在设备环境中指定新字体时,必须调用GetTextMetrixs函数来计算该字体中字符高度和字符平均宽度。如果你使用的是一个比例字体,注意字符平均宽度只是一个平均值,某些字符会更宽些,某些则会窄些。本章的后面会介绍如何确定一个由不同宽度字符组成的字符串总宽度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值