在同一行上绘制不同字体的文本

【勇芳软件工作室】汉化HomePreviousNext

字体系列中不同类型的样式可以有不同的宽度。例如,一个家庭的大胆和斜体风格总是比给定点大小的罗马风格宽。当您在一行中显示或打印多种类型样式时,必须跟踪线的宽度,以避免将字符显示或打印在一起。

您可以使用两个函数来检索当前字体中的文本的宽度(或范围)。GetTabbedTextExtent函数计算字符串的宽度和高度。如果字符串包含一个或多个制表符字符,则字符串的宽度将基于指定数组的制表符位置。GetTextExtentPoint32函数计算一行文本的宽度和高度。

必要时,Windows通过更改字符位图来合成字体。要以粗体字体合成一个字符,Windows会绘制两个字符:一次在起始点,再次在起始点右侧的一个像素。要以斜体字体合成字符,Windows会在字符单元底部绘制两行像素,将起始点向右移动一个像素,绘制下一行,并继续,直到绘制字符。通过移动像素,每个角色似乎被剪切到右边。剪切量是字符高度的函数。

写入包含多种字体的文本行的一种方法是在每次调用TextOut之后使用GetTextExtentPoint32函数,并将长度添加到当前位置。以下示例写入行“这是一个示例字符串”。使用粗体字符“This is a”,切换为“sample”的斜体字符,然后返回到“string”的粗体字符。打印完所有字符串后,恢复系统默认字符。

int XIncrement;

int YStart;

TEXTMETRIC tm;

HFONT hfntDefault, hfntItalic, hfntBold;

SIZE sz;

LPSTR lpszString1 = "This is a ";

LPSTR lpszString2 = "sample ";

LPSTR lpszString3 = "string.";

/ *创建一个粗体和斜体逻辑字体。*/

hfntItalic = MyCreateFont();

hfntBold = MyCreateFont();

/ *选择粗体字体并绘制第一个字符串* /

/ *从指定点开始(XIncrement,YStart)。*/

XIncrement = 10;

YStart = 50;

hfntDefault = SelectObject(hdc, hfntBold);

TextOut(hdc,XIncrement,YStart,lpszString1,

lstrlen(lpszString1));

/*

*计算第一个字符串的长度并添加

*这个值用于x-increment

*文本输出操作。

*/

GetTextExtentPoint32(hdc,lpszString1,

lstrlen(lpszString1), &sz);

XIncrement += sz.cx;

/*

*从TEXTMETRIC检索悬垂值

*结构,并从x增量中减去它。

*(这仅对非TrueType栅格是必需的

*字体。)

*/

GetTextMetrics(hdc, &tm);

XIncrement -= tm.tmOverhang;

/*

*选择斜体字体并绘制第二个字符串

*从点开始(XIncrement,YStart)。

*/

hfntBold = SelectObject(hdc, hfntItalic);

GetTextMetrics(hdc, &tm);

XIncrement -= tm.tmOverhang;

TextOut(hdc,XIncrement,YStart,lpszString2,

lstrlen(lpszString2));

/*

*计算第二个字符串的长度并添加

*这个值用于x-increment

*文本输出操作。

*/

GetTextExtentPoint32(hdc,lpszString2,lstrlen(lpszString2),& sz);

XIncrement += sz.cx;

/*

*重新选择粗体字并绘制第三个字符串

*从点开始(XIncrement,YStart)。

*/

SelectObject(hdc, hfntBold);

TextOut(hdc,XIncrement - tm.tmOverhang,YStart,lpszString3,

lstrlen(lpszString3));

/ *重新选择原始字体。*/

SelectObject(hdc, hfntDefault);

/ *删除粗体和斜体字体。*/

DeleteObject(hfntItalic);

DeleteObject(hfntBold);

在此示例中,GetTextExtentPoint32函数将初始化具有指定字符串长度和高度的SIZE结构的成员。GetTextMetrics函数检索当前字体的悬垂。因为如果字体是TrueType字体,悬垂值为零,则悬出值不会更改字符串放置。但是,对于栅格字体,使用突出值很重要。

如果字体是光栅字体,则从粗体字符串中减去突出部分一次,以使后续字符更接近字符串的末尾。因为悬垂影响光栅字体中斜体字符串的开头和结尾,所以字形从指定位置的右侧开始,并在最后一个字符单元的端点的左侧结束。(GetTextExtentPoint32函数检索字符单元格的范围,而不是字形的范围。)为了解释栅格斜体字符串中的悬垂,示例在放置字符串之前减去悬垂,并在放置后续字符之前再次减去。

SetTextJustification功能为文本行中的中断字符添加了额外的空间。您可以使用GetTextExtentPoint函数确定字符串的范围,然后从该行占用的总空间中减去该范围,并使用SetTextJustification函数在字符串中的中断字符之间分配额外的空格。SetTextCharacterExtra功能为所选字体中的每个字符单元增加了额外的空间,包括中断字符。(您可以使用GetTextCharacterExtra函数确定要添加到字符单元格的额外空间的当前量;默认设置为零。)

您可以使用GetCharWidth32GetCharABCWidths函数来更精确地放置字符,以检索字体中单个字符的宽度。GetCharABCWidths功能比GetCharWidth32功能更准确,但仅当与TrueType字体一起使用时;当您使用非TrueType字体的GetCharABCWidths时,它会检索与GetCharWidth32相同的信息。

ABC间距还允许应用程序执行非常精确的文本对齐。例如,当应用程序右对齐栅格罗马字体而不使用ABC间距时,前进宽度被计算为字符宽度。这意味着位图中字形右侧的空白对齐,而不是字形本身。通过使用ABC宽度,应用程序在对齐文本时,在放置和移除白色空间时具有更大的灵活性,因为它们具有允许它们精确控制字符间距的信息。