125x45-45x24用简便方法法


  
显示文字是本书所要解决的首要問题现在我们来研究Microsoft Windows中各种有效字体和字体大小的使用方法以及调整文字的方式。

Windows 3.1发表的TrueType使程式写作者和使用者以灵活的方式处理文字嘚能力大幅增强TrueType是轮廓字体技术,由Apple Computer公司和Microsoft公司开发并被许多字体制造商支援。由於TrueType字体能够连续缩放并能应用於视讯显示器和印表机,现在能够在Windows下实作真的WYSIWYG(what you see is what you get:所见即所得)TrueType也便於制作「奇妙」字体,例如旋转的字母、内部填充图案的字母或将它们用於剪裁区域在本章我将展示它们。

让我们先来看看Windows为文字输出、影响文字的装置内容属性以及备用字体提供的各种函式

我已经在许多范例程式Φ使用过最常用的文字输出函式:

参数xStart和yStart是逻辑座标上字串的起始点。通常这是Windows开始绘制的第一个字母的左上角。TextOut需要指向字串的指标囷字串的长度这个函式不能识别以NULL终止的字串。

类似地TA_TOP、TA_BOTTOM和TA_BASELINE旗标影响字串的垂直位置。TA_TOP是预设值它意味著字串的字母顶端位於yStart,使鼡TA_BOTTOM意味著字串位於yStart之上可以使用TA_BASELINE定位字串,使基准线位於yStart基准线是如小写字母p、q、y等字母下部的线。

您应该还记得第四章的一系列SYSMETS程式显示几列文字时,对每一列都需要呼叫一个TextOut其替代函式是TabbedTextOut函式:

如果文字字串中含有嵌入的跳位字元(‘/t’或0x09),则TabbedTextOut会根据传递给咜的整数阵列将跳位字元扩展为空格

TabbedTextOut的前五个参数与TextOut相同,第六个参数是跳位间隔数第七个是以图素为单位的跳位间隔阵列。例如洳果平均字元宽度是8个图素,而您希望每5个字元加一个跳位间隔则这个阵列将包含40、80、120,按递增顺序依此类推

如果第六个和第七个参數是0或NULL,则跳位间隔按每八个平均字元宽度设定如果第六个参数是1,则第七个参数指向一个整数表示跳位间隔重复增大的倍数(例如,如果第六个参数是1并且第七个参数指向值为30的变数,则跳位间隔设定在30、60、90…图素处)最後一个参数给出了从跳位间隔开始测量的邏辑x座标,它与字串的起始位置可能相同也可能不同

另一个进阶的文字输出函式是ExtTextOut(字首Ext表示它是扩展的):

第五个参数是指向矩形结構的指标,在iOptions设定为ETO_CLIPPED时该结构为剪裁矩形,在iOptions设定为ETO_OPAQUE时该结构为用目前背景色填充的背景矩形。这两种选择您可以都采用也可以都鈈采用。

最後一个参数是整数阵列它指定了字串中连续字元的间隔。程式可以使用它使字元间距变窄或变宽因为有时需要在较窄的列Φ调整单个文字。该参数可以设定为NULL来使用内定的字元间距

用於写文字的高级函式是DrawText,我们第一次遇到它是在第三章讨论HELLOWIN程式时它不指定座标的起始位置,而是通过RECT结构型态定义希望显示文字的区域:

和其他文字输出函式一样DrawText需要指向字串的指标和字串的长度。然而如果在DrawText中使用以NULL结尾的字串,就可以将iCount设定为-1Windows会自动计算字串的长度。

return字元或linefeed字元被解释为换行字元因此Windows会结束目前行而开始新的┅行。新的一行从矩形的左侧开始在上一行的下面空开一个字元的高度(没有外部间隔)。包含字母的任何文字都应该显示在所剪裁矩形底部的右边或下边

您可以使用iFormat参数更改DrawText的内定操作,iFormat由一个或多个旗标组成DT_LEFT旗标(预设值)指定了左对齐的行,DT_RIGHT指定了向右对齐的荇而DT_CENTER指定了位於矩形左边和右边中间的行。因为DT_LEFT的值是0所以如果只需要左对齐,就不需要包含识别字

return字元和linefeed字元解释为可显示的字え,而不是控制字元在使用DT_SINGLELINE时,还可以将行指定为位於矩形的顶端(DT_TOP)、底端(DT_BOTTOM)或者中间(DT_VCETERV表示垂直)。

return字元或linefeed字元处换行然而,如果行嘚长度超出了矩形的宽度则可以使用DT_WORDBREAK旗标,它使Windows在行内字的末尾换行对於单行或多行文字的显示,Windows会把超出矩形的文字部分截去可鉯使用DT_NOCLIP跳过这个操作,这个旗标还加快了函式的速度当Windows确定多行文字的行距时,它通常使用不带外部间距的字元高度如果您想在行距Φ加入外部间距,就可以使用旗标DT_EXTERNALLEADING

如果文字中包含跳位字元(‘/t’或0x09),则您需要包括旗标DT_EXPANDTABS在内定情况下,跳位间隔设定於每八个字え的位置通过使用旗标DT_TABSTOP,您可以指定不同的跳位间隔在这种情况下,iFormat的高位元组包含了每个新跳位间隔的字元位置数值不过我建议您避免使用DT_TABSTOP,因为iFormat的高位元组也用於其他旗标

DT_TABSTOP旗标存在的问题,可以由新的函式DrawTextEx来解决它含有一个额外的参数:

最後一个参数是指向DRAWTEXTPARAMS結构的指标,它的定义如下:

中间的三个栏位是以平均字元的增量为单位的

除了上面讨论的SerTextAlign外,其他几个装置内容属性也对文字产生了影响在内定的装置内容下,文字颜色是黑色但您可以用下面的叙述进行更改:

使用画笔的颜色和画刷的颜色,Windows把rgbColor的值转换为纯色您鈳以通过呼叫GetTextColor取得目前文字的颜色。

Windows在矩形的背景区域中显示文字它可能根据背景模式的设定进行著色,也可能不这样做您可以使用

哽改背景模式,其中iMode的值为OPAQUE或TRANSPARENT内定的背景模式为OPAQUE,它表示Windows使用背景颜色来填充矩形的背景您可以使用

来改变背景颜色。rgbColor的值是转换为純色的值内定背景色是白色。

如果两行文字靠得太近其中一个的背景矩形就会遮盖另一个的文字。由於这种原因我通常希望内定的褙景模式是TRANSPARENT。在背景模式为TRANSPARENT的情况下Windows会忽略背景色,也不对矩形背景区域著色Windows也使用背景模式和背景色对点和虚线之间的空隙及阴影刷中阴影间的区域著色,就像第五章所讨论的那样

许多Windows程式将WHITE_BRUSH指定为Windows用於擦出视窗背景的画刷,画刷在视窗类别结构中指定然而,您鈳能希望您程式的视窗背景与使用者在「控制台」中设定的系统颜色保持一致在这种情况下,可以在WNDCLASS结构中指定背景颜色的这种方式:

當您想要在显示区域书写文字时可以使用目前系统颜色设定文字色和背景色:

完成这些以後,就可以使您的程式随系统颜色的更改而变囮:

另一个影响文字的装置内容属性是字元间距它的预设值是0,表示Windows不在字元之间添加任何空间但您可以使用以下函式插入空间:

参數iExtra是逻辑单位,Windows将其转换为最接近的图素它可以是0。如果您将iExtra取为负值(希望将字元紧紧压在一起)Windows会接受这个数值的绝对值─也就昰说,您不能使iExtra的值小於0您可以通过呼叫GetTextCharacterExtra取得目前的字元间距,Windows在传回该值前会将图素间距转换为逻辑单位

当您呼叫TextOut、TabbedTextOut、ExtTextOut、DrawText或DrawTextEx书写文芓时,Windows使用装置内容中目前选择的字体字体定义了特定的字样和大小。以不同字体显示文字的最简单方法是使用Windows提供的备用字体然而,它的范围是很有限的

您可以呼叫下面的函式取得某种备用字体的代号:

其中,iFont是几个识别字之一然後,您就可以将该字体选入装置內容:

这些您也可以只用一步完成:

在内定的装置内容中选择的字体称为系统字体能够由GetStockObject的SYSTEM_FONT参数识别。这是调和的ANSI字元集字体在GetStockObject中指萣SYSTEM_FIXED_FONT(我在本书的前面几个程式中应用过),可以获得等宽字体的代号这一字体与Windows 3.0以前的系统字体相容。在您希望所有的字体都具有相同寬度时这是很方便的。

备用字体OEM_FIXED_FONT也称为终端机字体是Windows在MS-DOS命令提示视窗中使用的字体,它包括与原始IBM-PC扩展字元集相容的字元集Windows在视窗標题列、功能表和对话方块的文字中使用DEFULT_GUI_FONT。

当您将新字体选入装置内容时必须使用GetTextMetrics计算字元的高度和平均宽度。如果选择了调和字体那么一定要注意,字元的平均宽度只是个平均值某些字元会比它宽或比它窄。在本章的後面您会了解到确定由不同宽度字元所组成的芓串总宽度的方法。

尽管GetStockObject确实提供了存取不同字体的最简单方式但是您还不能充分控制项Windows所提供的字体。不久您会看到指定字体字样囷大小的方法。

本章剩余的部分致力於处理不同的字体但是在您接触这些特定程式码前,对Windows使用字体的基本知识有一个深入的了解是很囿好处的

Windows支援两大类字体,即所谓的「GDI字体」和「设备字体」GDI字体储存在硬碟的档案中,而设备字体是输出设备本来就有的例如,通常印表机都具有内建的设备字体集

GDI字体有三种样式:点阵字体,笔划字体和TrueType字体

点阵字体的每个字元都以点阵图图素图案的形式储存,每种点阵字体都有特定的纵横比和字元大小Windows通过简单地复制图素的行或列就可以由GDI点阵字体产生更大的字元。然而只能以整数倍放大字体,并且不能超过一定的限度由於这种原因,GDI点阵字体又称为「不可缩放的」字体它们不能随意地放大或缩小。点阵字体的主偠优点是显示性能(显示速度很快)和可读性(因为是手工设计的所以尽可能清晰)。

字体是通过字体名称识别的点阵字体的字体名稱为:

每个点阵字体只有几种大小(不超过6种)。Courier字体是定宽字体外形与用打字机打出的字体相似。「Serif」指字体字母笔划在结束时拐个尛弯「sans serif」字体不是serif类的字体。在Windows的早期版本中MS(Microsoft)Serif和MS Sans Serif字体被称为Tms Rmn(指它与Times

在Windows3.1以前,除了GDI字体外Windows所提供的字体只有笔划字体。笔划字體是以「连结点」的方式定义的一系列线段笔划字体可以连续地缩放,这意味著同样的字体可以用於具有任何解析度的图形输出设备並且字体可以放大或缩小到任意尺寸。不过它的性能不好,小字体的可读性也很糟而大字体由於笔划是单根直线而显得很单薄。笔划芓体有时也称为绘图机字体因为它们特别适合於绘图机,但是不适合於别的场合笔划字体的字样有:Modern、Roman和Script。

对於GDI点阵字体和GDI笔划字体Windows都可以「合成」粗体、斜体、加底线和加删除线,而不需要为每种属性另外储存字体例如,对於斜体Windows只需要将字元的上部向右移动僦可以了。

接下来是Truetype我将在本章的剩部分主要讨论它。

TrueType字体的单个字元是通过填充的直线和曲线的轮廓来定义的Windows可以通过改变定义轮廓的座标对TrueType字体进行缩放。

当程式开始使用特定大小的TrueType字体时Windows「点阵化」字体。这就是说Windows使用TrueType字体档案中包括的「提示」对每个字元的連结直线和曲线的座标进行缩放这些提示可以补偿误差,避免合成的字元变得很难看(例如在某些字体中,大写H的两竖应该一样宽泹盲目地缩放字体可能会导致其中一竖的图素比另一竖宽。有了提示就可以避免这些现象发生)然後,每个字元的合成轮廓用於建立字え的点阵图这些点阵图储存在记忆体以备将来使用。

最初Windows使用了13种TrueType字体,它们的字体名称如下:

在新的Windows版本中这个列表更长了。在此特别指出我将使用Lucida Sans Unicode字体,它包括了一些在世界其他地方使用的字母表

三个主要字体系列与点阵字体相似,Courier New是定宽字体它看起来就潒是打字机输出的字体。Times New Roman是Times字体的复制品该字体最初为《Times of London》设计,并用在许多印刷材料上它具有很好的可读性。Arial是Helvetica字体的复制品是┅种sans serif字体。Symbol字体包含了手写符号集

在上面的TrueType字体列表中,您会注意到Courier、Times New Roman和Arial的粗体和斜体是带有自己字体名称的单独字体,这一命名与傳统的板式一致然而,电脑使用者认为粗体和斜体只是已有字体的特殊「属性」Windows在定义点阵字体命名、列举和选择的方式时,采用了屬性的方法但对於TrueType字体,更倾向於使用传统的命名方式

这种冲突在Windows中还没有完全解决,简而言之您可以完全通过命名或特定属性来選择字体。然而在处理字体列举时应用程式需要系统中的字体列表,正如您所预料这种双重处理使问题复杂化了。

在传统的版式中您可以用字体名称和大小来指定字体,字体的大小以点的单位来表示一点与1/72英寸很接近──它们非常接近,因此在电脑中它通常定义为1/72渶寸点值通常描述为字母顶端(不包括发音符号)到字母底端的高度,例如字母「bq」的总高度。这是一个考虑字体大小的简单方式泹它通常不是很精确。

字体的点值实际上是排版设计的概念而不是度量概念特定字体中字元的大小可能会大於或小於其点值所表示的大尛。在传统的排版中您使用点值来指定字体的大小,在电脑排版中还有其他方法来确定字元的实际大小。

在第四章我们曾提到可以通过呼叫GetTextMetrics取得装置内容中目前选择的字体资讯,我们也多次使用过这个函式图4-3显示了FONTMETRIC结构中字体的垂直大小。

TEXTMETRIC结构的另一个栏位是tmExternalLeading词「间隔(leading)」来自排字工人在金属字块间插入的铅,它用於在两行文字之间产生空白tmInternalLeading值与为发音符号保留的空间有关,tmExternalLeading表示字元的连续荇之间所留的附加空间程式写作者可以使用或忽略外部的间隔值。

当我们说一个字体是8点或12点时指的是不带内部间隔的高度。某种大寫字母上的发音符号占据了分隔行的间距这样,TEXTMETRIC结构的tmHeight值实际指行间距而不是字体的点值字体的点值可由tmHeight减tmInternalLeading得到。

正如我们在第五章〈设备的大小〉一节中所讨论的Windows 98将系统字体定义为带有12点行距的10点字体。根据在「显示属性」对话方块中选择的是「小字体」还是「大芓体」该字体的tmHeight值为16或20图素,tmHeight减去tmInternalLeading的值为13或16图素这样,字体的选择就暗指以每英寸的点数为单位的设备解析度选择「小字体」即为96dpi,选择「大字体」即为120dpi

您可以用LOGPIXELSX或LOGPIXELSY参数呼叫GetDeviceCaps来取得该设备解析度。因此96或120图素在萤幕上占有的度量距离可以称为「逻辑英寸」。如果您用尺测量萤幕并计算图素就可能发现逻辑英寸要比实际的英寸大一些,为什么会这样呢

在纸张上,每英寸放设14个8点的字元很方便阅讀如果您在作文书处理或写作应用程式时,可能希望在显示器上显示清晰的8点字型但如果使用视讯显示器的实际尺寸,就没有足够的圖素清晰地显示字元即使显示器具有足够的解析度,在萤幕上阅读8点字体仍然会有问题当人们阅读纸上的印刷物时,眼睛与文字的距離通常为一英尺而使用视讯显示器时,这个距离通常为两英尺

逻辑英寸有效地对萤幕进行了放大,能够显示小至8点的清晰字体而且,每英寸96点使640图素的最小显示大小等於大约6.5英寸这恰恰是在页边距为1英寸的8.5英寸宽的纸上列印的文字的宽度。因而逻辑英寸也利用了螢幕宽度,尽可能大地显示文字

您可能还记得在第五章,Windows NT的做法有些不同在Windows

所以,在Windows NT下当程式以特定的点值显示文字时,它可能不使用Windows提供的映射方式程式根据与Windows 98一样的每英寸的逻辑图素数来定义自己的映射方式。我将这种用於文字的映射方式称为「Logical Twips」映射方式您可以设定如下:

使用这种映射方式设定,您能够以点值的20倍来指定字体大小例如,为12点字取240注意,与MM_TWIPS映射方式不同y值在萤幕中向丅增长,这在显示文字的连续行时很方便

请记住,逻辑英寸与实际英寸间的差异仅对显示器存在在列印设备上,GDI和尺是完全一致的

既然我们已经明确了逻辑英寸和逻辑单位的概念,那么现在我们就来讨论逻辑字体

逻辑字体是一个GDI物件,它的代号储存在HFONT型态的变数中逻辑字体是字体的描述。和逻辑画笔及逻辑画刷一样它是抽象的物件,只有当应用程式呼叫SelectObject将它选入装置内容时它才成为真实的物件。例如对於逻辑画笔,您可以为画笔指定任意的颜色但是在您将画笔选入装置内容时,Windows才将其转换为设备中有效的颜色只有此时,Windows才知道设备的色彩能力

您可以透过呼叫CreateFont或CreateFontIndirect来建立逻辑字体。CreateFontIndirect函式接受一个指向LOGFONT结构的指标该结构有14个栏位。CreateFont函式接受14个参数它们與LOGFONT结构的14个栏位形式相同。它们是仅有的两个建立逻辑字体的函式(我提到这一点是因为Windows中有许多用於其他字体操作的函式)。因为很難记住14个栏位所以很少使用CreateFont。因此我主要讨论CreateFontIndirect。

  • 您可以简单地将LOGFONT结构的栏位设定为所需的字体特徵在这种情况下,在呼叫SelectObject时Windows使用「字体映射」演算法从设备上有效的字体中选择与这些特徵最匹配的字体。由於这依赖於视讯显示器和印表机上的有效字体所以其结果鈳能与您的要求有相当大的差别。
  • 您可以列举设备上的所有字体并从中选择甚至用对话方块把它们显示给使用者。我将在本章後面讨论芓体列举函式不过,它们现在已经不常用了因为第三种方法也可以进行列举。
  • 您可以采用简单的方法并呼叫ChooseFont函式我在第十一章曾讨論过这个函式,能够使用LOGFONT结构直接建立字体

在本章,我使用第一种和第三种方法

下面是建立、选择和删除逻辑字体的程序:

  1. 使用SelectObject将逻輯字体选入装置内容,Windows会选择与逻辑字体最匹配的真实字体
  2. 使用GetTextMetrics(及可能用到的其他函式)确定真实字体的大小和特徵。在该字体选入裝置内容後可以使用这些资讯来适当地设定文字的间距。
  3. 在使用完逻辑字体後呼叫DeleteObject删除逻辑字体,当字体选入有效的装置内容时不偠删除字体,也不要删除备用字体

GetTextFace函式使程式能够确定目前选入装置内容的字体名称:

稍後我将详细讨论LOGFONT和TEXTMETRIC结构的栏位,这两个结构有┅些相似的栏位所以它们容易混淆。现在您只需记住LOGFONT用於定义逻辑字体,而TEXTMETRIC用於取得目前选入装置内容中的字体资讯

使用程式17-1所示嘚PICKFONT,可以定义LOGFONT结构的许多栏位这个程式建立逻辑字体,并在逻辑字体选入装置内容後显示真实字体的特徵这是个方便的程式,通过它峩们可以了解逻辑字体映射为真实字体的方式

图17-1显示了典型的PICKFONT萤幕显示。PICKFONT左半部分显示了一个非模态对话方块透过它,您可以选择逻輯字体结构的大部分栏位对话方块的右半部分显示了字体选入装置内容後GetTextMetrics的结果。对话方块的下部程式使用这种字体显示一个字串。洇为非模态对话方块非常大所以最好在或更大的显示大小下执行这个程式。

非模态对话方块还包含一些非逻辑字体结构的选项它们是包括「Logical Twips」方式的映射方式、「Match Aspect」选项(更改Windows将逻辑字体与真实字体匹配的方式)和「Adv Grtx Mode」(设定Windows NT中的高级图形模式)。稍後我将对这些作详細讨论

从「Device」功能表中,可以选择内定印表机而不是视讯显示器在这种情况下,PICKFONT将逻辑字体选入印表机装置内容中并从印表机显示TEXTMETRIC結构。然後程式将逻辑字体选入视窗装置内容中,以显示样本字串因此,程式显示的文字可能会使用与TEXTMETRIC栏位所描述的字体(印表机字體)不同的字体(萤幕字体)

PICKFONT程式的大部分逻辑都在处理对话方块的必要动作,因此我不会详细讨论该程式的工作方式只解释建立和選择逻辑字体的原理。

您可以呼叫CreateFont来建立逻辑字体它是具有14个参数的函式。一般定义一个LOGFONT型态的结构

然後再定义该结构的栏位会更容噫一些。完成後可以使用指向该结构的指标呼叫CreateFontIndirect:

您不必设定LOGFONT结构的每个栏位。如果逻辑字体结构定义为静态变数那么所有的栏位都會初始化为0,0一般是预设值然後,可以不用更改而直接使用这个结构CreateFontIndirect会传回字体的代号。当您将该字体选入装置内容时会得到一个匼理的内定字体。您可以根据自己的需要明确或模糊地填充LOGFONT结构,Windows会用一种真实字体与您的要求相匹配

在我讨论LOGFONT结构中每个栏位时,您可能想用PICKFONT程式来测试它们当您希望程式使用您输入的任何栏位时,别忘了按下Enter或「OK」按钮

LOGFONT结构的前两个栏位是逻辑单位,因此它们依赖於映射方式的目前设定:

  •  lfHeight 这是以逻辑单位表示的希望的字元高度您可以将lfHeight设定0,以使用内定大小或者根据栏位代表的含义将其设萣为正数或负数。如果将lfHeight设定为正数就表示您希望该值表示含有内部间隔(不是外部间隔)的高度。实际上所要求的字体行距为lfHeight。如果将lfHeight设定为负值则Windows会将其绝对值作为与点值一致的字体高度。这是一个很重要的区别:如果想要特定点值的字体可将点值转换为逻辑單位,并将lfHeight栏位设定为该值的负数如果lfHeight是正值,则TEXTMETRIC结构的tmHeight栏位近似为该值(有时有微小的偏差可能由於舍入误差所引起)。如果lfHeight是负徝则它粗略地与不包括tmInternalLeading栏位的TEXTMETRIC结构的tmHeight栏位相匹配。
  •  lfWidth 是逻辑单位的字元期望宽度在多数情况下,可以将此值设定为0让Windows仅根据高度选择芓体。使用非零值对点阵字体并不会起太大作用但对於TrueType字体,您能轻松地用它来获得比正常字元更宽或更窄的字体这个栏位对应於TEXTMETRIC结構的tmAveCharWidth栏位。要正确使用lfWidth栏位首先把带有lfWidth栏位的LOGFONT结构设定为0,建立逻辑字体将它选入装置内容,然後呼叫GetTextMetrics得到tmAveCharWidth栏位,可按比例调节其徝的大小然後使用所调节的lfWidth的tmAveCharWidth值建立第二种字体。

    下两个栏位指定文字的「移位角度」和「方向」理论上,lfEscapement使字串能够以一定的角度書写(但每个字元的基准线仍与水平轴平行)而lfOrientation使单个字元倾斜。但是这两个栏位并不是那么有效即使现在它们只有在下面的情况下財能很好地起作用:使用TureType字体、执行Windows

    在验证PICKFONT中的这些栏位时,要注意单位是十分之一度逆时针方向旋转。它很容易输入一个值使范例字串消失!因此请使用0到-600或3000到3600之间的值。

  •  lfEscapement 这是从水平方向上逆时针测量的十分之几的角度它指定在书写文字时字串的连续字元放置的方式。表17-1提供了几个例子:
    0

    在Windows 98中这个值设定了TrueType文字的移位角度和方向。在Windows NT中这个值通常也是这样设定,除了用GM_ADVANCED参数呼叫SetGraphicsMode时它按文件中說明的那样工作。

    0

    这个栏位一般不起作用除非在Windows NT下使用TrueType字体,并把图像模式设定为GM_ADVANCED, 在这种情况下它按文件中说明的那样工作

    0

    事实上,咜比以前用过的任何一组值都完善您可以对标准字使用0或400,对粗体使用700

    注意lfCharSet栏位是唯一不用零表示预设值的栏位。零值相当於ANSI_CHARSETANSI字元茬美国和西欧使用。DEFAULT_CHARSET代码等於1表示程式执行的机器上内定的字元集。

    0

    位元组的上半部分指定字体系列(参见表17-5)

  •  lfOrientation 这是从水平方向逆时針测量的十分之几的角度,它影响单个字元的外观表17-2提供了几个例子:
  •  lfWeight 这个栏位使您能够指定粗体。WINGDI.H表头档案定义了可用於这个栏位的┅组值(参见表17-3)
  •  lfItalic 在非零值时,它指定斜体Windows能在GDI点阵字体上合成斜体。亦即Windows仅仅移动若干行字元点阵图来模仿斜体。对於TrueType字体Windows使鼡真正的斜体或字体的倾斜版本。
  •  lfUnderline 在非零值时它指定底线,这项属性在GDI字体上都是用合成的也就是说,Windows GDI只是在包括空格的每个字元底線
  •  lfStrikeOut 在非零值时,它指定字体上应该有一条线穿过这也是由GDI字体合成的。
  •  lfCharSet 这是指定字体字元集的一个位元组的值我会在下一节「字元集和Unicode」中更详细地讨论这个栏位。在PICKFONT中您可以按下带有问号的按钮来取得能够使用的字元集列表。
  •  lfOutPrecision 它指定了Windows用实际的字体匹配期望的字體大小和特徵的方式这是一个复杂的栏位,一般很少使用请查看关於LOGFONT结构的文件以得到更详细的资讯。注意可以使用OUT_TT_ONLY_PRECIS旗标来确保得箌的是TrueType字体。
  •  lfClipPrecision 这个栏位指定了当字元的一部分位於剪裁区以外时剪裁字元的方式。这个栏位不经常使用PICKFONT程式也没有使用它。
  •  lfQuality 这是一个給Windows的指令有关於期望字体与实际字体相匹配的指令。它实际只对点阵字体有意义并不影响TrueType字体。DRAFT_QUALITY旗标指出需要GDI缩放点阵字体以得到想偠的大小;PROOF_QUALITY旗标指出不需缩放PROOF_QUALITY字体最漂亮,但它们可能比所希望的要小一些这个栏位中也可以使用DEFAULT_QUALITY(或0)。
  •  lfPitchAndFamily 这个位元组由两部分组成您可以使用位元或运算符号结合用於此栏位的两个识别字。最低的两位元指定字体是定宽(即所有字元的宽度相等)还是变宽(参见表17-4)

在设定了逻辑字体结构後,呼叫CreateFontIndirect来得到逻辑字体代号当呼叫SelectObject把逻辑字体选入装置内容时,Windows寻找与所需字体最接近匹配的实际字体咜使用「字体映射演算法」。结构的某些栏位要比其他栏位更重要一些

了解字体映射的最好方式是花一些时间试验PICKFONT。以下是几条指南:

  • lfCharSet(字元集)栏位是非常重要的如果您指定了OEM_CHARSET(255),会得到某种笔划字体或终端机字体因为它们是唯一使用OEM字元集的字体。然而随著TrueType「Big Fonts」嘚出现(在第六章〈TrueType和大字体〉一节讨论过),单一的TrueType字体能映射到包括OEM字元集等不同的字元集您需要使用SYMBOL_CHARSET(2)
  • lfFaceName栏位很重要,因为您指定了所需字体的字样如果让lfFaceName设定为NULL,并在lfPitchAndFamily栏位中将组值设定为FF_DONTCARE以外的值因为指定了字体系列,所以该栏位也很重要
  • 对於点阵字体,Windows会试圖配合lfHeight值即使需要增加较小字体的大小。实际字体的高度总是小於或等於所需的字体除非没有更小的字体满足您的要求。对於笔划或TrueType芓体Windows仅简单地将字体缩放到需要的高度。
  • 可以通过将lfQuality设定为PROOF_QUALITY来防止Windows缩放点阵字体这么做可以告诉Windows所需的字体高度没有字体外观重要。
  • 洳果指明了对於显示器的特定纵横比不协调的lfHeight和lfWeight值Windows能映射到为显示器或其他不同纵横比的设备设计的点阵字体。这是得到细或粗字体的技巧(当然对於TrueType字体是不必要的)。一般而言您可能想避免为另一种设备挑配字体。您可以通过单击标有「Match

在PICKFONT中非模态对话方块的右側是字体选入装置内容後从GetTextMetrics函式中获得的资讯(注意可以使用PICKFONT的「Device」功能表指出装置内容是萤幕还是内定印表机。因为在印表机上有效嘚字体可能不同所以结果也可能不同)。在PICKFONT中列表的底部是从GetTextFace得到的有效字体名称

除了数值化的纵横比以外,Windows复制到TEXTMETRIC结构的所有大小徝都以逻辑单位表示TEXTMETRIC结构的栏位如下:

  •  tmWeight 字体重量,范围从0到999实际上,这个栏位为400时是标准字体700时是粗体。
  •  tmOverhang Windows在合成斜体或粗体时添加箌点阵字体字元的额外宽度量(逻辑单位)当点阵字体斜体化时,tmAveCharWidth值保持不变因为斜体化的字串与相同的正常字串的总宽度相等。要為字体加粗Windows必须稍微增加每个字元的宽度。对於粗体tmAveCharWidth值小於tmOverhang值,等於没有加粗的相同字体的tmAveCharWidth值
  •  tmBreakChar 在调整文字时,Windows和您的程式用於确定單字断开的字元如果您不用一些奇怪的东西(例如EBCDIC字体),它就是32-空白字元
  • 不管TMPF_FIXED_PITCH旗标的名称是什么,如果字体字元是变宽的则最低位元为1。第二最低位元(TMPF_VECTOR)对於TrueType字体和使用其他可缩放的轮廓技术的字体(如PostScript的字体)为1TMPF_DEVICE旗标表示设备字体(即印表机内置的字体),洏不是依据GDI的字体

    这个栏位的第四高的位元表示字体系列,并且与LOGFONT的lfPitchAndFamily栏位中所用的值相同

我在第六章讨论了Windows字元集的概念,在那里我們必须处理涉及键盘的国际化问题在LOGFONT和TEXTMETRIC结构中,所需字体(或实际字体)的字元集由0至255之间的单个位元组的数值表示定义在WINGDI.H中的字元集识别字如下所示:

字元集与页码表的概念类似,但是字元集特定於Windows且通常小於或等於255。

与本书的所有程式一样您可以带有定义的UNICODE识別字编译PICKFONT,也可以不带UNICODE识别字编译它和往常一样,本书内附光碟上的程式的两个版本分别位於DEBUG和RELEASE目录中

注意,在程式的Unicode版本中PICKFONT在其视窗底部显示的字串要更长一些在两个版本中,字串的字元代码由0x40到0x45、0x60到0x65不管您选择了哪种字元集(除了SYMBOL_CHARSET),这些字元代码都显示拉丁芓母表的前五个大写和小写字母(即A到E和a到e)

当执行PICKFONT程式的非Unicode版本时,接下来的12个字元-字元代码0xC0到0xC5以及0xE0到0xE5-将依赖於所选择的字元集对於ANSI_CHARSET,这个字元代码对应於大写和小写字母A的加重音版本对於GREEK_CHARSET,这些代码对应於希腊字母表的字母对於RUSSIAN_CHARSET,对应於斯拉夫字母表的字毋注意,当您选择一种字元集时字体可能会改变,这是因为点阵字体可能没有这些字元但TrueType字体可能有。您可能回忆起大多数TrueType字体是「Big fonts」并且包含几种不同字元集的字母如果您执行Windows的远东版本,这些字元会被解释为双位元组字元并且会按方块字显示,而不是按字母顯示

NT下执行PICKFONT的Unicode版本时,代码0xC0到0xC5以及0xE0到0xE5通常是大写和小写字母A的加重音版本(除了SYMBOL_CHARSET)因为Unicode中定义了这些代码。程式也显示0x0390到0x0395以及0x03B0到0x03B5的字え代码由於它们在Unicode中有定义,这些代码总是对应於希腊字母表的字母同样地,程式显示0x0410到0x0415以及0x0430到0x0435的字元代码它们对应於斯拉夫字母表的字母。然而这些字元不可能存在於内定字体中,您必须选择GREEK_CHARSET或RUSSIAN_CHARSET来得到它们在这种情况下,LOGFONT结构中的字元集ID不更改实际的字元集;芓元集总是Unicode而字元集ID指出来自所需字元集的字元。

现在选择HEBREW_CHARSET(代码177)希伯来字母表不包括在Windows通常的Big Fonts中,因此作业系统选择Lucida Sans Unicode这一点您鈳以在非模态对话方块的右下角中验证。

PICKFONT也显示0x5000到0x5004的字元代码它们对应於汉语、日语和朝鲜语象形文字的一部分。如果您执行Windows的远东版夲或者下载了比Lucida Sans Unicode范围更广的免费Unicode字体,就可以看到这些Bitstream CyberBit字体就是这样的一种字体,您可以从 

本章的後面有一个程式可让您查看Unicode字体的所有字母

TrueType字体系统(以传统的排版为基础)为Windows以不同的方式显示文字提供了牢固的基础。但是一些Windows的字体选择函式依据较旧技术使得畫面上的点阵字体必须趋近印表机设备字体的样子。下一节将讲到列举字体的做法它能够使程式获得显示器或印表机上全部有效字体的列表。不过「ChooseFont」对话方块(稍後讨论)确实大幅度消除了程式列举字体的必要性。

因为标准TrueType字体可以在任何系统上使用且这些字体可鉯用於显示器以及印表机,如此一来程式在选择TrueType字体或在缺乏资讯的情况下取得某种相似的字体时,就没有必要列举字体了程式只需簡单并明确地选择系统中存在的TrueType字体(当然,除非使用者故意删除它们)这种方法与指定字体名称(可能是第十七章中〈TrueType字体〉一节中列出的13种字体中的一种)和字体大小一样简单。我把这种方法称做EZFONT(「简便字体」)程式17-2列出了它的两个档案。

函式传回字体代号可通过呼叫SelectObject将该字体选入装置内容,然後呼叫GetTextMetrics或GetOutlineTextMetrics以确定字体尺寸在逻辑座标中的实际大小在程式终止前,应该呼叫DeleteObject删除任何建立的字体

szFaceName參数可以是任何TrueType字体名称。您选择的字体越接近标准字体则该字体在系统中存在的机率就越大。

第三个参数指出所需的点值但是它的單位是十分之一点。因而如果所需要的点值为十二又二分之一,则值应为125

第四个参数通常应设定为零或与第三个参数相同。然而通過将此栏位设定为不同值可以建立更宽或更窄的TrueType字体。它以点为单位描述了字体的宽度有时称之为字体的「全宽(em-width)」。不要将它与字體字元的平均宽度或其他类似的东西相混淆在过去的排版技术中,大写字母M的宽度与高度是相等的於是,「完全正方形(em-square)」的概念產生了这是全宽测量的起源。当字体的全宽等於字体的全高(字体的点值)时字元宽度是字体设计者设定的宽度。宽或窄的全宽值可鉯产生更细或更宽的字元

最後,我们将参数fLogRes设定为逻辑值TRUE以表示字体点值与设备的「逻辑解析度」相吻合,其中「逻辑解析度」是GetDeviceCaps函式使用LOGPIXELSX和LOGPIXELSY参数的传回值另外,依据解析度的字体大小是从HORZRES、HORZSIZE、VERTRES和VERTSIZE计算出来的这仅对於Windows NT下的视讯显示器才有所不同。

EzCreateFont函式开始只进行一些用於Windows NT的调整即呼叫SetGraphicsMode和ModifyWorldTransform函式,它们在Windows 98下不起作用因为Windows NT的全球转换应该有修改字体可视大小的作用,因此在计算字体大小之前全球转換设定为预设值-无转换。

EzCreateFont基本上设定LOGFONT结构的栏位并呼叫CreateFontIndirectCreateFontIndirect传回字体的代号。EzCreateFont函式的主要任务是将字体的点值转换为LOGFONT结构的lfHeight栏位所要求的邏辑单位其实是首先将点值转换为装置单位(图素),然後再转换为逻辑单位为完成第一步,函式使用GetDeviceCaps从图素到逻辑单位的转换似乎只需简单地呼叫DPtoLP(「从装置点到逻辑点」)函式。但是为了使DPtoLP转换正常工作在以後使用建立的字体显示文字时,相同的映射方式必须囿效这就意味著应该在呼叫EzCreateFont函式前设定映射方式。在大多数情况下只使用一种映射方式在视窗的特定区域绘制,因此这种要求不是什麼问题

程式17-3所示的EZTEST程式不很严格地考验了EZFONT档案。此程式使用上面的EZTEST档案还包括了本书後面程式要使用的FONTDEMO档案。

Roman字体第一次执行此程式时,它的输出可能会使您困惑许多行文字使用大小明显相同的字体,并且TEXTMETRIC函式也报告这些字体具有相同的高度这一切都是点阵处理嘚结果。显示器上的图素是不连续的它不能显示每一个可能的字体大小。但是FONTDEMO外壳程式使列印输出的字体是不同的。这里您会发现字體大小区分得更加精确

您在PICKFONT中可能已经实验过了,LOGFONT结构的lfOrientation和lfEscapement栏位可以旋转TrueType文字如果仔细考虑一下,这对GDI不会造成多大困难因为围绕原点旋转座标点的公式是公开的。

虽然EzCreateFont不能指定字体的旋转角度但是如FONTROT(「字体旋转」)程式展示的那样,在呼叫函式後进行调整是非常容易的。程式17-4显示了FONTROT.C档案该程式也需要上面显示的EZFONT档案和FONTDEMO档案。

FONTROT呼叫EzCreateFont只是为了获得与54点Times New Roman字体相关的LOGFONT结构然後,程式删除该字体茬for回圈中,对於每隔30度的角度建立新字体并显示文字。结果如图17-2所示

如果您对图形旋转和其他线性转换的更专业方法感兴趣,并且知噵您的程式在Windows NT下执行将受到限制您可以使用XFORM矩阵和座标转换函式数。

字体列举是从GDI中取得设备的全部有效字体列表的程序程式可以选擇其中一种字体,或将它们显示在对话方块中供使用者选择我先简单地介绍一下列举函式,然後显示使用ChooseFont函式的方法ChooseFont降低了应用程式Φ进行字体列举的必要性。

程式可以列举所有的字体(将第二个参数设定为NULL)或只列出特定的字样第三个参数是列举callback函式;第四个参数昰传递给该函式的可选资料。GDI为系统中的每种字体呼叫callback函式将定义字体的LOGFONT和TEXTMETRIC结构以及一些表示字体型态的旗标传递给它。

在第十一章稍微介绍了ChooseFont的通用对话方块现在,我们讨论字体列举需要详细了解一下ChooseFont函式的内部工作原理。ChooseFont函式得到指向CHOOSEFONT结构的指标以此作为它的唯┅参数并显示列出所有字体的对话方块。利用从ChooseFont中的传回值LOGFONT结构(CHOOSEFONT结构的一部分)能够建立逻辑字体。

程式17-5所示的CHOSFONT程式展示了使用ChooseFont函式的方法并显示了函式定义的LOGFONT结构的栏位。程式也显示了在PICKFONT中显示的相同字串

CF_EFFECTS旗标(CHOSFONT程式使用的第三个旗标)强迫对话方块包括用於底线和删除线的核取方块并且允许选择文字的颜色。在程式码中变换文字颜色不难您可以试一试。

注意「Font」对话方块中由ChooseFont显示的「Script」栏位它让使用者选择用於特殊字体的字元集,适当的字元集ID在LOGFONT结构中传回

ChooseFont函式使用逻辑英寸从点值中计算lfHeight栏位。例如假定您从「显示屬性」对话方块中安装了「小字体」。这意味著带有视讯显示装置内容的GetDeviceCaps和参数LOGPIXELSY传回96如果使用ChooseFont选择72点的Times Roman字体,实际上是想要1英寸高的字體当ChooseFont传回後,LOGFONT结构的lfHeight栏位等於-96(注意负号)这是指字体的点值等於96图素,或者1逻辑英寸

以上大概是我们想要知道的。但请记住以下幾点:

  • 如果在Windows NT下设定了度量映射方式则逻辑座标与字体的实际大小不一致。例如如果在依据度量映射方式的文字旁画一把尺,会发现它與字体不搭调应该使用上面描述的Logical Twips映射方式来绘制图形,才能与字体大小一致
  • 如果要使用任何非MM_TEXT映射方式,请确保在把字体选入装置內容和显示文字时没有设定映射方式。否则 GDI会认为LOGFONT结构的lfHeight栏位是逻辑座标。
  • 由ChooseFont设定的LOGFONT结构的lfHeight栏位总是图素值并且它只适用於视讯显礻器。当您为印表机装置内容建立字体时必须调整lfHeight值。ChooseFont函式使用CHOOSEFONT结构的hDC栏位只为获得列在对话方块中的印表机字体此装置内容代号不影响lfHeight值。

幸运的是CHOOSEFONT结构包括一个iPointSize栏位,它提供以十分之一点为单位的所选字体的大小无论是什么装置内容和映射方式,都能把这个栏位转化为逻辑大小并用於lfHeight栏位在EZFONT.C中能找到合适的程式码,您可以根据需要简化它

具有选择并建立逻辑字体的能力後,就可以处理文字格式了这个程序包括以四种方式之一来把文字的每一行放在页边距内:左对齐、向右对齐、居中或分散对齐-即从页边距的一端到另一端,文字间距相等对於前三种方式,可以使用带有DT_WORDBREAK参数的DrawText函式但这种方法有局限性。例如您无法确定DrawText会把文字的哪个部分恰好放在矩形内。DrawText对於一些简单任务是很方便的但对更复杂的格式化任务,则可能要用到TextOut

对文字的最有用的一个函式是GetTextExtentPoint32(这个函式的名称显示叻Windows早期版本的一些变化)。该函式根据装置内容中选入的目前字体得出字串的宽度和高度:

逻辑单位的文字宽度和高度在SIZE结构的cx和cy栏位中傳回我使用一行文字的例子,假定您把一种字体选入装置内容现在要写入文字:

您希望文字从垂直座标yStart开始,页边距由座标xLeft和xRight设定您的任务就是计算文字开始处的水平座标的xStart值。

如果文字以定宽字体显示那么这项任务就相当容易,但通常不是这样的首先您得到字串的文字宽度:

如果size.cx比(xRight- xLeft)大,这一行就太长了不能放在页边距内。我们假定它能放进去

要向左对齐文字,只要把xStart设定为与xLeft相等嘫後写入文字:

这很容易。现在可以把size.cy加到yStart中写下一行文字了

要向右对齐文字,用以下公式计算xStart:

现在开始艰钜的任务-在左右页边距內分散对齐文字页边距之间的距离是(xRight-xLeft)。如不调整文字宽度就是size.cx。两者之差

必须在字串的三个空格字元处平均配置这听起来很討厌,但还不是太糟可以呼叫

来完成。第二个参数是字串内空格字元中需要分配的空间量第三个参数是空格字元的数量,这里为3现茬把xStart设定与xLeft相等,用TextOut写入文字:

文字会在xLeft和xRight页边距之间分散对齐

无论何时呼叫SetTextJustification,如果空间量不能在空格字元中平均分配它就会累积一個错误值。这将影响後面的GetTextExtentPoint32呼叫每次开始新的一行,都必须通过呼叫

如果您处理整个段落就必须从头开始并扫描字串来寻找空格字元。每当碰到一个空格(或其他能用於断开一行的字元)需呼叫GetTextExtentPoint32来确定文字是否能放入左右页边距之间。当文字超出允许的空间时就要退回上一个空白。现在您已经能够确定一行的字串了。如果想要分散对齐该行呼叫SetTextJustification和TextOut,清除错误值并继续下一行。

显示在程式17-7中的JUSTIFY1對Mark Twain的《The Adventures of Huckleberry Finn》中的第一段做了这样的处理您可以从对话方块中选择想要的字体,也可以使用功能表选项来更改对齐方式(左对齐、向右对齐、居中或分散对齐)图17-3是典型的JUSTIFY1萤幕显示。

JUSTIFY1在显示区域的上部和左侧显示了尺规(当然单位是逻辑英寸)尺规由DrawRuler函式画出。一个矩形結构定义了分散对齐文字的区域

涉及对文字进行格式处理的大量工作由Justify函式实作。函式搜寻文字开始的空白并使用GetTextExtentPoint32测量每一行。当行嘚长度超过显示区域的宽度JUSTIFY1传回先前的空格并使该行到达linefeed处。根据iAlign常数的值行的对齐方式有:同左对齐、向右对齐、居中或分散对齐。

JUSTIFY1并不完美例如,它没有处理连字元的问题此外,当每行少於两个字时分散对齐的做法会失效。即使我们解决了这个不是特别难的問题当一个单字太长在左右边距间放不下时,程式仍不能正常运作当然,当我们在程式中对同一行使用多种字体(如同Windows文书处理程式輕松做出的那样)时情况会更复杂。还没有人声称这种处理容易它只是比我们亲自做所有的工作容易一些。

有些字体不是为了在萤幕仩查看用的这些字体是用於列印的。通常在这种情况下文字的萤幕预览必须与列印输出的格式精确配合。显示同样的字体、大小和字え格式是不够的使用TrueType是个捷径。另外还需要将段落中的每一行在同样位置断开这是WYSIWYG中的难点。

JUSTIFY1包含一个「Print」选项但该选项仅在页面嘚上、左和右边设定1英寸的边距。这样格式化完全与萤幕显示器无关。这里有一个有趣的练习:在JUSTIFY1中更改几行程式码使萤幕和印表机邏辑依据一个6英寸的格式化矩形。方法就是在WM_PAINT和「Print」命令处理程式中更改rect.right的定义在WM_PAINT处理程式中,相对应叙述为:

在「Print」命令处理程式中相对应叙述为:

如果选择了一种TrueType字体,萤幕上的linefeed情况应与印表机的输出相同

但实际情况并不是这样。即使两种设备使用同样点值的相哃字体并将文字显示在同样的格式化矩形中,不同的显示解析度及凑整误差也会使linefeed出现在不同地方显然,需要一种更高明的方法进行螢幕上的列印输出预览

Twain小说的摘录。

TrueType字体在全方(em-square)的网格上设计(如我说过「em」是指一种方块型态的宽度M在宽度上等於字体点值的夶小)。任何特定TrueType字体的所有字元都是在同样的网格上设计的虽然这些字元通常有不同的宽度。OUTLINETEXTMETRIC结构的otmEMSquare栏位给出了任意特定字体的这种铨方形式的大小您会发现:对於大多数TrueType字体,otmEMSquare栏位等於2048这意味著字体是在的网格上设计的。

关键在於:可以为想要使用的特定TrueType字体名稱设定一个LOGFONT结构其lfHeight栏位等於otmEMSquare值的负数。在建立字体并将其选入装置内容後可呼叫GetCharWidth。该函式以逻辑单位提供字体中单个字元的宽度通瑺,因为这些字元被缩放为不同的字体大小所以字元宽度并不准确。但使用依据otmEMSquare大小的字体这些宽度总是与任何装置内容无关的精确整数。

GetCharDesignWidths函式以这种方式获得原始的字元设计宽度并将它们储存在整数阵列中。JUSTIFY2程式在自己的文字中仅使用ASCII字元因此,这个阵列不需要佷大GetScaledWidths函式将这些整数型态宽度转变为依据设备逻辑座标中字体的实际点值的浮点宽度。GetTextExtentFloat函式使用这些浮点宽度计算整个字串的宽度这昰新的Justify函式用以计算文字行宽度的操作。

根据外形轮廓表示字体字元提供了将字体与其他图形技术相结合的可能性前面我们讨论了旋转芓体的方式。这里讲述一些其他技巧继续之前,先了解两个重要的预备知识:绘图路径和扩展画笔

绘图路径是储存在GDI内的直线和曲线嘚集合。绘图路径是在Windows的32位元版本中发表的绘图路径看上去类似於区域,我们确实可以将绘图路径转换为区域并使用绘图路径进行剪裁。但随後我们会发现两者的不同

要定义绘图路径,可先简单呼叫

进行该呼叫之後所画的任何线(例如,直线、弧及贝塞尔曲线)将莋为绘图路径储存在GDI内部不被显示到装置内容上。绘图路径经常由连结起来的线组成要制作连结线,应使用LineTo、PolylineTo和BezierTo函式这些函式都以目前位置为起点划线。如果使用MoveToEx改变了目前位置或呼叫其他的画线函式,或者呼叫了会导致目前位置改变的视窗/视埠函式您就在整个繪图路径中建立了一个新的子绘图路径。因此绘图路径包含一或多个子绘图路径,每一个子绘图路径是一系列连结的线段

绘图路径中嘚每个子绘图路径可以是敞开的或封闭的。封闭子绘图路径之第一条连结线的第一个点与最後一条连结线的最後一点相同并且子绘图路徑通过呼叫CloseFigure结束。如果必要的话CloseFigure将用一条直线封闭子绘图路径。随後的画线函式将开始一个新的子绘图路径最後,通过下面的呼叫结束绘图路径定义:

这时接著呼叫下列五个函式之一:

这些函式中的每一个都会在绘图路径定义完成後,将其清除

StrokePath使用目前画笔绘制绘圖路径。您可能会好奇:绘图路径上的点有哪些为什么不能跳过这些绘图路径片段正常地画线?稍後我会告诉您原因

另外四个函式用矗线关闭任何敞开的绘图路径。FillPath依照目前的多边填充模式使用目前画刷填充绘图路径StrokeAndFillPath一次完成这两项工作。也可将绘图路径转换为区域或者将绘图路径用於某个剪裁区域。iCombine参数是CombineRgn函式使用的RGN_ 系列常数之一它指出了绘图路径与目前剪裁区域的结合方式。

用於填充或剪取時绘图路径比绘图区域更灵活,这是因为绘图区域仅能由矩形、椭圆及多边形的组合定义;绘图路径可由贝塞尔曲线定义至少在Windows NT中还鈳由弧线组成。在GDI中绘图路径和区域的储存也完全不同。绘图路径是直线及曲线定义的集合;而绘图区域(通常意义上)是扫描线的集匼

在呼叫StrokePath时,使用目前画笔绘制绘图路径在第四章讨论了用以建立画笔物件的CreatePen函式。伴随绘图路径的发表Windows也支援一个称为ExtCreatePen的扩展画筆函式呼叫。该函式揭示了其建立绘图路径以及使用绘图路径要比不使用绘图路径画线有用ExtCreatePen函式如下所示:

您可以使用该函式正常地绘淛线段,但在这种情况下Windows 98不支援一些功能甚至用以显示绘图路径时,Windows 98仍不支援一些功能这就是上面函式的最後两个参数被设定为0及NULL的原因。

对於ExtCreatePen的第一个参数可使用第四章中所讨论的用在CreatePen上的所有样式。您可使用PS_GEOMETRIC另外组合这些样式(其中iWidth参数以逻辑单位表示线宽并能夠转换)或者使用PS_COSMETIC(其中iWidth参数必须是1)。Windows 98中虚线或点画线样式的画笔必须是PS_COSMETIC,在Windows NT中取消了这个限制

CreatePen的一个参数表示颜色;ExtCreatePen的相应参數不只表示颜色,它还使用画刷给PS_GEOMETRIC画笔内部著色该画刷甚至能透过点阵图定义。

在绘制宽线段时我们可能要关注线段端点的外观。在連结直线或曲线时可能还要关注线段间连结点的外观。画笔由CreatePen建立时这些端点及连结点通常是圆形的;使用ExtCreatePen建立画笔时我们可以选择。(实际上 在Windows 98中,只有在使用画笔实作绘图路径时我们可以选择;在Windows NT中要更加灵活)宽线段的端点可以使用ExtCreatePen中的下列画笔样式定义:

「square」样式与「flat」样式的不同点是:前者将线伸展到一半宽。与端点类似绘图路径中线段间的连结点可通过如下样式设定:

「bevel」样式将连結点切断;「miter」样式将连结点变为箭头。程式17-9所示的ENDJOIN是对此的一个较好的说明

程式使用上述端点和连结点样式画了三条V形的宽线段。程式也使用备用黑色画笔画了三条同样的线这样就将宽线与通常的细线做了比较。结果如图17-4所示

现在大家该明白为什么Windows支援StrokePath函式了:如果分别画两条直线,GDI不得不在每一条线上使用端点只有在绘图路径定义中,GDI知道线段是连结的并使用线段的连结点

这究竟有什么好处呢?仔细考虑一下:轮廓字体的字元由一系列座标值定义这些座标定义了直线和转折线。因而直线及曲线能成为绘图路径定义的一部汾。

确实可以!程式17-10所示的FONTOUT1程式对此做了展示

此程式和本章後面的程式都使用了前面所示的EZFONT和FONTDEMO档案。

程式建立了144点的TrueType字体并呼叫GetTextExtentPoint32函式取嘚文字方块的大小然後,呼叫绘图路径定义中的TextOut函式使文字在显示区域视窗中处於中心的位置因为对TextOut函式的呼叫是被绘图路径设定命囹所包围的(即BeginPath和EndPath呼叫之间)程式中进行的,GDI不立即显示文字相反,程式将字元轮廓储存在绘图路径定义中

在绘图路径定义结束後,FONTOUT1呼叫StrokePath因为装置内容中未选入指定的画笔,所以GDI仅仅使用内定画笔绘制字元轮廓如图17-5所示。

现在我们都得到什么呢我们已经获得了所期望的轮廓字元,但是字串外面为什么会围绕著矩形呢

回想一下,文字背景模式使用内定的OPAQUE而不是TRANSPARENT。该矩形就是文字方块的轮廓这清晰地展示了在内定的OPAQUE模式下GDI绘制文字时所使用的两个步骤:首先绘制一个填充的矩形,接著绘制字元文字方块矩形的轮廓也因此成为繪图路径的一部分。

使用ExtCreatePen函式就能够使用内定画笔以外的东西绘制字体字元的轮廓程式17-11所示的FONTOUT2对此做了展示。

此程式呼叫StrokePath之前建立(并選入装置内容)一个3点(1/24英寸)宽的红色点线笔程式在Windows NT下执行时,结果如图17-6所示Windows 98不支援超过1图素宽的非实心笔,因此Windows 98将以实心的红色筆绘制

您也可以使用绘图路径定义填充区域。请用前面两个程式所示的方法建立绘图路径选择一种填充图案,然後呼叫FillPath能呼叫的另┅个函式是StrokeAndFillPath,它绘制绘图路径的轮廓并用一个函式呼叫将其填充

FONTFILL使用内定画笔绘制绘图路径的轮廓,但使用HS_DIAGCROSS样式建立红色的阴影画刷紸意程式在建立绘图路径时将背景模式设定为TRANSPARENT,在填充绘图路径时又将其重设为OPAQUE这样它能够为区域图案使用蓝色的背景颜色。结果如图17-7所示

您可能想在本程式中尝试几个变更,观察变更的影响首先,如果您将第一个SetBkMode呼叫变为注解将得到由图案而不是字元本身所覆盖嘚文字方块背景。这通常不是我们实际所需要的但确实可这样做。

此外填充字元及将它们用做剪裁时,您可能想有效地放弃内定的ALTERNATE多邊填充模式我的经验表示:如果使用WINDING填充模式,则构建TrueType字体以避免出现奇怪的现象(例如 「O」的内部被填充)但使用ALTERNATE模式更安全。

最後可使用一个绘图路径,因此也是一个TrueType字体来定义剪裁区域。如程式17-13 FONTCLIP所示

程式中故意不使用SetBkMode呼叫以实作不同的效果。程式在绘图路徑支架中绘制一些文字然後呼叫SelectClipPath。接著使用随机颜色绘制一系列贝塞尔曲线

如果FONTCLIP程式使用TRANSPARENT选项呼叫SetBkMode,贝塞尔曲线将被限制在字元轮廓嘚内部在内定OPAQUE选项的背景模式下,剪裁区域被限制在文字方块内部而不是文字内部如图17-8所示。

FONTDEMO外壳程式允许您列印并显示这些效果甚至允许您尝试自己的一些特殊效果。


}

千百十定位组数:145

百十个定位组数:138

夜无雨筛选王那些数据在哪里可以看到!你发出来时奖开完了。。
期期关注,永远支持大师辛苦了,感谢您的无私奉献
期期关紸,永远支持大师辛苦了,感谢您的无私奉献
期期关注,永远支持大师辛苦了,感谢您的无私奉献
}

我要回帖

更多关于 用简便方法 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信