字体处理
本章解释了 Cocoa 文本系统如何处理字体。它解释了如何在应用程序中使用字体面板、如何直接使用字体对象以及如何使用字体管理器。
字体面板
字体面板,也称为字体窗口,是一个用户界面对象,显示可用字体系列和样式的列表,让用户预览它们并更改用于显示文本的字体。文本对象,例如NSTextView
,与NSFontPanel
和NSFontManager
对象来实现 AppKit 的字体转换系统。默认情况下,文本对象使用其选择中的第一个字体或其键入属性保持“字体”面板更新。它还会更改显示文本的字体,以响应来自“字体”面板和“字体”菜单的消息。此类更改适用于富文本对象的选定文本或键入属性或纯文本对象中的所有文本。
NSFontManager
是字体转换的中心——也就是说,改变字体对象的特征,比如它的大小或字体。字体管理器从“字体”面板接收消息,并将消息向上发送到响应器链以对文本对象进行操作。
通常,应用程序的字体面板显示所有标准字体系统上可用。如果这不适合您的应用程序——例如,如果只应使用固定间距字体——您可以为NSFontPanel
对象分配一个委托以过滤可用字体。在NSFontPanel
对象将特定字体系列或字体添加到其列表之前,NSFontPanel
对象会询问其委托 通过向代表发送一个确认添加 fontManager:willIncludeFont:
信息。如果委托返回TRUE
(或未实现此方法),则添加字体。如果委托返回FALSE
,则不会添加字体。必须在加载主 nib 文件之前调用此方法。
创建字体面板
通常,您将字体面板的功能以及NSFontManager
对象和字体菜单添加到您的应用程序中,用户可以通过它们使用界面生成器打开字体面板. 您可以通过拖动“字体”或“格式”菜单来执行此操作(其中包含一个字体子菜单)到您的应用程序的菜单之一。在运行时,字体面板对象被创建并连接到字体转换系统中。您还可以使用sharedFontPanel
类方法。
您可以使用以下方法将自定义视图对象添加到NSFontPanel
对象setAccessoryView:
,允许您将自定义控件添加到“字体”面板。您还可以通过将委托分配给应用程序的字体管理器对象来限制显示的字体(默认情况下,显示所有字体)。
如果你想要 NSFontManager
对象从除 之外的某个类实例化字体面板NSFontPanel
,使用NSFontManager
类方法setFontPanelFactory:
. 有关使用字体转换系统的更多信息,请参阅手动转换字体。
使用字体面板
您可以使用NSTextView
(or NSText
) 方法 启用文本对象和字体面板之间的交互setUsesFontPanel:
方法。对于用作字段编辑器的文本视图,建议这样做, 例如。
您可以在标准文本字段以外的对象上使用“字体”面板。该NSFontManager
方法setAction:
设置在选择新字体时发送到第一响应者链的操作(由选择器指定)。默认选择器是changeFont:
. 任何从响应者链接收此消息的对象都应该发送一个convertFont:
消息返回到NSFontManager
以用户指定的方式转换字体。
– (void)changeFont:(id)sender
{
NSFont *oldFont = [自己的字体];
NSFont *newFont = [sender convertFont:oldFont];
[self setFont:newFont];
返回;
}
如果选择了多种字体,则changeFont:
必须为每个选择的字体发送转换消息。这对于诸如表格视图之类的对象非常有用,这些对象本身不会响应来自字体面板的消息。
使用字体对象
计算机字体是 OpenType 或 TrueType 等格式的数据文件,包含描述一组字形的信息,如字符和字形中所述,以及字形渲染中使用的各种补充信息。本NSFont
类提供用于获取和设置字体信息的接口。一个NSFont
实例提供了访问字体的特点和字形。文本系统结合字符信息和字体信息来选择在文本布局期间使用的字形。您可以通过将字体对象传递给接受它们作为参数的方法来使用它们。字体对象是不可变的,因此在您的应用程序的多个线程中使用它们是安全的。
您不使用alloc
和init
方法创建字体对象;相反,您可以使用诸如fontWithName:matrix:
或 之类的方法fontWithName:size:
来查找可用字体并根据需要更改其大小或矩阵。这些方法检查具有指定特征的现有字体对象,如果有则返回它。否则,他们查找请求的字体数据并创建适当的对象。您还可以使用字体描述符来创建字体。请参阅字体描述符。
NSFont
还定义了一些用于指定系统标准字体,如方法systemFontOfSize:
,userFontOfSize:
和messageFontOfSize:
。要请求这些标准字体的默认大小,请传递0
或负数作为字体大小。查询标准字体变体中列出了标准系统字体方法。
字体描述符
从NSFontDescriptor
类实例化的字体描述符提供了一种用属性字典描述字体的方法。然后可以使用字体描述符来创建或修改NSFont
对象。特别是,您可以NSFont
从字体描述符创建一个对象,您可以从一个NSFont
对象中获取一个描述符,您可以更改一个描述符并使用它来创建一个新的字体对象。您还可以使用字体描述符来指定应用程序提供的自定义字体。
字体描述符提供了一种字体匹配功能,您可以通过该功能通过创建一个字体描述符来部分描述字体,例如,仅使用一个系列名称。然后,您可以使用matchingFontDescriptorsWithMandatoryKeys:
.
可以存档字体描述符,这比存档字体对象更可取,因为字体对象是不可变的,并且提供对安装在特定系统上的特定字体的访问。另一方面,字体描述符根据字体的特征、属性来描述字体,并在运行时提供对与这些属性匹配的当前可用字体的访问。
也就是说,您可以使用字体描述符向系统查询匹配特定属性的可用字体,然后创建NSFont
匹配这些属性的实例,例如名称、特征、语言和其他功能。例如,您可以使用字体描述符检索与给定字体系列名称匹配的所有字体,使用 PostScript 系列名称(由 CSS 标准定义),如清单 6-1所示。
清单 6-1 字体家族名称匹配
NSFontDescriptor *helveticaNeueFamily =
[NSFontDescriptor fontDescriptorWithFontAttributes:
@{ NSFontFamilyAttribute: @"Helvetica Neue" }];
NSArray *匹配 =
[helveticaNeueFamily 匹配FontDescriptorsWithMandatoryKeys: nil];
该matchingFontDescriptorsWithMandatoryKeys:
方法如图返回的所有系统上的Helvetica Neue字体的字体,例如字体描述符的数组HelveticaNeue
,HelveticaNeue-Medium
,HelveticaNeue-Light
,HelveticaNeue-Thin
,等。(在给定 OS X 安装上可用字体的 PostScript 字体和字体系列名称由字体手册应用程序显示在“字体信息”窗口中。)
查询字体指标
NSFont
当该信息可用时,定义了许多用于访问字体度量信息的方法。方法,例如boundingRectForGlyph:
,boundingRectForFont
,xHeight
,等等,所有对应于标准字体的度量信息。图 6-1显示了字体度量如何应用于字形维度,表 6-1列出了与度量相关的方法名称。有关更具体的信息,请参阅各种方法说明。
字体度量 | 方法 |
---|---|
| |
查询标准字体变体
使用方法 NSFont
表6-2中列出的,您可以查询所有的标准字体变化。请求标准字体的默认字体大小,您可以显式传入默认大小(从systemFontSize
和等类方法获得labelFontSize
),或传入0
或负值。
字体 | 方法 |
---|---|
系统字体 | |
强调系统字体 | |
小系统字体 | |
强调小系统字体 | |
迷你系统字体 | |
强调迷你系统字体 |
|
应用字体 | |
应用固定间距字体 | |
标签字体 |
字符、字形和布局管理器
字符是与书面语言单位相对应的概念实体。通常,字形是字符的具体渲染图像。(排印概念提供了对字符和字形的更详细的讨论。)
在英语中,字符和字形之间通常存在一对一的映射,但情况并非总是如此。例如,字形“ö”可以是两个字符的结果,一个代表基本字符“o”,另一个代表变音符号“¨”。文字处理器的用户可以按一次箭头键将插入点从“ö”字形的一侧移动到另一侧;但是,字符流中的当前位置必须增加 2 以说明构成单个字形的两个字符。
因此,文本系统必须管理两个相关但不同的数据流:字符流(及其属性)和从这些字符派生的字形流。所述NSTextStorage
对象存储的归属字符和NSLayoutManager
对象存储所导出的字形。找到这两个流之间的对应关系是布局管理器的责任。例如,当用户选择一系列文本时,使用屏幕上显示的字形,布局管理器必须确定与选择对应的字符范围。
删除字符后,可能需要重新绘制某些字形。例如,如果用户从单词“feel”中删除字符“ee”,那么“f”和“l”现在相邻并且可以用“fl”连字而不是两个字形“f”和“f”来表示。 “我”。该NSLayoutManager
对象指示字形生成器对象根据需要生成新的字形。一旦字形重新生成,文本必须被布置和显示。使用NSTextContainer
文本系统的对象和其他对象,布局管理器确定每个字形在文本视图中出现的位置。最后,文本视图呈现文本。
因为NSLayoutManager
对象是文本系统操作的核心,所以它也充当系统各个组件共享的信息存储库。有关更多信息NSLayoutManager
,请参阅NSLayoutManager 类参考和文本布局编程指南。
获取字形的视图坐标
字形位置相对于放置它们的线段的边界矩形的原点进行计算。要在其容器坐标中获取字形线条片段的矩形,请使用NSLayoutManager
方法lineFragmentRectForGlyphAtIndex:effectiveRange:
。然后将该矩形的原点添加到 返回locationForGlyphAtIndex:
的字形位置以获取容器坐标中的字形位置。
以下来自CircleView示例代码项目的代码片段说明了这种技术。
usedRect = [layoutManager usedRectForTextContainer:textContainer];
NSRect lineFragmentRect = [layoutManager lineFragmentRectForGlyphAtIndex:glyphIndex
有效范围:NULL];
NSPoint viewLocation, layoutLocation = [layoutManager
locationForGlyphAtIndex:glyphIndex];
// 这里 layoutLocation 是字形布局的位置(在容器坐标中)。
layoutLocation.x += lineFragmentRect.origin.x;
layoutLocation.y += lineFragmentRect.origin.y;
使用字体管理器
任何记录用户可以更改的字体的对象都应该告诉字体管理器 每当它成为第一响应者时,其选择的字体是什么当它是第一响应者时,每当它的选择发生变化时。该对象通过向共享字体管理器发送一个setSelectedFont:isMultiple:
信息。它应该传入选择的第一种字体,以及一个指示是否有多个字体的标志。
字体管理器使用此信息更新字体面板 和字体菜单以反映选择中的字体。例如,假设字体是 Helvetica Oblique 12.0 点。在这种情况下,字体面板会选择该字体并显示其名称;字体菜单在其斜体命令前添加了一个复选标记;如果没有可用的 Helvetica 粗体变体,则禁用粗体菜单项;等等。
创建字体管理器
你通常设置一个字体管理器 和字体菜单 使用界面生成器. 但是,您也可以通过获取共享字体管理器实例并让它在运行时创建标准字体菜单来以编程方式执行此操作,如下例所示:
NSFontManager *fontManager = [NSFontManager sharedFontManager];
NSMenu *fontMenu = [fontManager fontMenu:YES];
然后,您可以将字体菜单添加到应用程序的菜单中。安装字体菜单后,您的应用程序将自动获得字体菜单和字体面板的功能.
处理字体更改
用户通常通过操作“字体”面板来更改选择的字体(也称为字体窗口)和字体菜单。这些对象通过向字体管理器发送操作消息来启动预期的更改. 有四种改变字体的动作方法:
前三个使字体管理器查询消息的发送者,以确定要添加或删除的特征,或者如何修改字体。最后一个使字体管理器使用字体面板中的设置来修改字体。字体管理器记录 此信息并在以后的请求中使用它来转换字体。
当字体管理器收到一个addFontTrait:
orremoveFontTrait:
消息时,它会用一条tag
消息查询发送者,将返回值解释为一个特征掩码以供使用convertFont:toHaveTrait:
或者 convertFont:toNotHaveTrait:
,如手动转换字体中所述。例如,字体菜单命令斜体和粗体分别具有NSItalicFontMask
和 的特征掩码值NSBoldFontMask
。请参阅NSFontManager 类参考中的常量部分以获取特征掩码值列表。
当字体管理器收到一条modifyFont:
消息时,它会用一条tag
消息查询发送者,并将返回值解释为要执行的特定类型的转换,通过手动转换字体中描述的各种转换方法。例如,标签值为 的按钮SizeUpFontAction
会导致字体管理器的convertFont:
方法来增加NSFont
作为参数传递的对象的大小。有关转化标记值列表,请参阅NSFontManager
方法modifyFont:
。
对于modifyFontViaPanel:
,字体管理器向应用程序的字体面板发送一个panelConvertFont:
信息。字体面板依次使用字体管理器根据用户的选择转换提供的字体。例如,如果用户只选择字体面板中的字体系列(可能是 Helvetica),那么对于提供给 的任何字体panelConvertFont:
,只更改系列:Courier Medium 10.0 点变成 Helvetica Medium 10.0 点,Times Italic 12.0 点变成Helvetica Oblique 12.0 点。
字体管理器 响应字体变化 通过发送一个动作方法 changeFont:
响应者链上的动作消息。接收此消息的文本承载对象应该让字体管理器通过调用来转换其选择中的字体convertFont:
对于每种字体并使用NSFont
返回的对象。该convertFont:
方法使用改变字体动作方法记录的信息,如addFontTrait:
,适当修改提供的字体。(无法显式设置字体更改操作或特征;相反,您可以使用手动转换字体中描述的方法。)
这个简单的例子假设选择中只有一种字体:
- (void)changeFont:(id)sender
{
NSFont *oldFont = [self selectionFont];
NSFont *newFont = [sender convertFont:oldFont];
[自设置SelectionFont:newFont];
返回;
}
大多数带有文本的对象必须扫描具有不同字体的范围的选择,并convertFont:
为每个范围调用。
手动转换字体
NSFontManager
定义了许多显式转换的方法字体的特定特征和特征。表 6-3列出了这些转换方法。
每个方法都返回所提供字体的转换版本,如果无法转换,则返回原始字体。
字体转换的默认实现非常保守,只有在没有其他特征或方面受到影响时才进行更改。例如,如果您尝试通过添加粗体特征来转换 Helvetica Oblique 12.0 点,并且只有 Helvetica Bold 可用,则不会转换字体。您可以创建一个子类NSFontManager
并覆盖转换方法以执行不那么保守的转换,可能在这种情况下使用 Helvetica Bold 并失去 Oblique 特性。
除了字体转换方法, NSFontManager
定义 fontWithFamily:traits:weight:size:
构造具有给定特征集的字体。如果您不想创建 的子类NSFontManager
,则可以使用此方法自行执行近似字体转换。
设置字体样式和特征
本节介绍如何在属性字符串中以编程方式设置字体样式(例如粗体或斜体)和字体属性(例如下划线)。
下划线是一个可以使用NSUnderlineStyleAttributeName
常量轻松设置在属性字符串上的属性,如NSMutableAttributedString 类参考中所述。使用以下方法:
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)aRange
通过NSUnderlineStyleAttributeName
对名与参数值的[NSNumber numberWithInt:1]
。
与下划线不同,粗体和斜体是字体的特征,因此您需要使用字体管理器实例将字体转换为具有所需特征,然后将字体属性添加到可变属性字符串中。对于名为 的可变属性字符串attributedString
,请使用以下技术:
NSFontManager *fontManager = [NSFontManager sharedFontManager];
无符号 idx = range.location;
NSRange 字体范围;
NSFont *字体;
而(NSLocationInRange(idx,范围)){
font = [attributedString 属性:NSFontAttributeName atIndex:idx
最长有效范围:&fontRange inRange:range];
fontRange = NSIntersectionRange(fontRange, range);
[attributedString applyFontTraits:NSBoldFontMask range:fontRange];
idx = NSMaxRange(fontRange);
}
如果您的可变属性字符串实际上是一个NSTextStorage
对象,请将此代码放在beginEditing
和 endEditing
调用。
检查字体
除了转换字体, NSFontManager
提供有关哪些字体可用于应用程序以及任何给定字体的特征的信息。这availableFonts
方法返回所有可用字体名称的数组。这availableFontNamesWithTraits:
方法根据字体特征掩码过滤可用字体。
有三种方法可以检查单个字体。这fontNamed:hasTraits:
true
如果字体与提供的特征掩码匹配,则方法返回。这traitsOfFont:
方法返回给定字体的特征掩码。这weightOfFont:
方法返回字体粗细在 0-15 范围内的近似排名,其中 0 是可能的最轻权重,5 是正常或书本粗细,9 相当于粗体,而 15 是最重的(通常称为黑色或超黑)。
自定义字体转换系统
如果需要自定义字体通过创建NSFontManager
or 的子类来转换系统NSFontPanel
,您必须NSFontManager
使用setFontManagerFactory:
或者 setFontPanelFactory:
消息,在创建共享字体管理器或共享字体面板之前。这些方法将您的类记录为第一次实例化字体管理器的类或请求字体面板。如果您只需要向“字体”面板添加一些自定义控件,则可以避免使用子类。在这种情况下,您可以调用该NSFontPanel
方法setAccessoryView:
NSView
在其字体浏览器下方添加一个对象。
如果您提供自己的字体菜单,您应该使用字体管理器将其注册 setFontMenu:
方法。字体管理器负责验证字体菜单项并根据所选字体更改其标题和标签。例如,当所选字体为斜体时,字体管理器会在斜体字体菜单项中添加一个复选标记并将其标记更改为UnitalicMask
。您的字体菜单项应该使用适当的操作方法和标签,如表 6-4所示。
字体菜单项 | 行动 | 标签 |
---|---|---|
斜体 |
| |
大胆的 |
| |
较重 |
| |
更大 |
|