字体和文本布局(Fonts and TextLayout)

来源:互联网 发布:淘宝宝贝关键词 编辑:程序博客网 时间:2024/06/05 15:56

Fonts and Text Layout

你可以使用Java 2D API变换和绘制机制来处理文本字符串。另外,Java 2D API提供了文本相关的类来支持更自然(fine-grain)的字体控制和高级的文本布局。这些包含了一个增强的Font类和一个新的TextLayout类中。

这一部分把注意力放在了通过java.awt和java.at.font包中的类和接口提供兼容性支持的新的字体和文本布局上。关于这一部分更多信息请访问http://developer.java.sun.com/developer/onlineTraining/Graphics/2DText/.

关于文本的分析及国际化,请查阅java.text中相关文档以其Java手册上的“书写国际化程序”部分。
关于在Swing如何使用文本布局机制,请阅java.awt.swing.text文档及Java手册上"使用JFC/Swing包"部分。

4.1 相关的接口与类
Interfaces and Classes

下面列出了主要的字体和文本布局相关的类和接口。这些类和接口大多在java.awt.font包中。但为了保持JDK向后的兼容性,像Font等类则在java.awt包中。




      

      
4.2 文本理念
Font Concepts

Font类被增强用于支持详细的字体信息说明,并使使用高级的印刷上的特点成为可能。

Font对象表示了系统上可用的字面集中的字体的实例。常用的字面如Helvetica Bold和Courier Bold Italic.

Font关联到三种不同的名称——逻辑(logical)名称、字系(font family)名称和字面(font face)名称:

(1) Font的逻辑名称是平台上指定的字体名称相映射的名称。逻辑名称从JDK1.1和更早期的版本中就开始使用。当在Java 2 SDK中指定一个Font时,你应该使用字面名称而不是逻辑名称。你可以通过调用getName获得字体的逻辑名称。如果想获得平台上所有映射到指定字体的逻辑名称,我可以调用jaav.awt.Tookit.getFontList
(2) Font的字系名称是这样的名称,它通过几个诸如Helvetica等字面来决定印刷时的策略。你能通过调用getFamily方法获得字系名称。
(3) Font的字面名称引用系统上实际安装了的字体。当你在java 2 SDK指定一个字体时,你应该使用这个名称。它经常作为字体的名称来引用。你可以通过调用getFontName来获得字体名称。如果想知道在你的系统上可用的字面的名称,请调用GraphicsEnvironment.getAllFonts方法。

能可以通过调用getAttributes方法来获得Font的信息;Font的属性包括它的名称、大小、变换及像权值和姿势等字体特点。

LineMetrics对象包含了Font的测量信息,像它的上行(ascent)、下行(descent)及首先(leading)信息等:

(1) Ascent 定义了基线到上行线的距离。这个距离表示大写字母的典型高度,但一些字符可能会超出这个高度。
(2)Descent 定义了基线到下行线的距离。大多字符的最低点是在下行线的范围内,但也有些字符可能会比下行线低。
(3) Leading 是从下行线到下一行的顶点的推荐距离。



这些信息用于定义同一行上字符的恰当位置以其邻近行之间的位置。你可以访问这些行度量值通过调用getAscent、getDescent和getLeading方法。你也可以通过LineMetrics访问字体的高度、基线、删除线等字体信息。

4.3 文本布局理念
Text Layout Concepts

在文本显示前,它必须使用恰当的字形和连字符来形成并定位。这个过程被称作文本布局(text layout)。文本布局过程如下:
(1) 使用恰当的字形和连字符形成文本;
(2) 恰当的排列这些字符;
(3) 检测并定位文本。

这些用于布局文本的信息同样对于以下操作也是必要的:补字号定位、冲突检测和字符加亮等。
为了开发能在国际环境下部署的软件,文本必须被以一种遵守合适的书写系统的方式来显示不同语言。

4.3.1形成文本
Shaping Text

字形是对一个或多个字符的直观的表示。字形的形状、大小和位置取决于它所在的环境。很多不同的字形可以用来表示单独的字符或字符的组合,这都取决于字体和样式。

举例来说,在手写草书文本中,一个特定的字符可以呈现出不同的形状,这取决于和它相连的字符的及其连接方式。

在一些书写系统中,尤其阿拉伯地区的,字形所处的环境必须考虑进去。和英语不同,草书在阿拉伯语中是必须的;如果没有使用草书形式,这在阿拉伯地区是不受欢迎的。

根据上下文的不同,这些草书形式在形状上可以有根本性的不同。如下所示,阿拉伯字母heh有四种不同的草书形式:


尽管这四种形式彼此间是完全不同的,这些草书形状的改变并不是根本不同于英语中的草书书写。

在一些上下文中,两个字形甚至可以根本性的改变形状并组合成一种新的形状。这种字形的组合方式称为连体字。例如,大多英文字体包含连体字“fi”,如下图所示。这种组合把"f"伸出了部分,并以一种更自然的方式呈现,而不是简单的把字母贴在一起。


连体字两样也被用于阿拉伯文字中,并且某些连体字是强制性的,某些字符组合如果没有使用恰当的连体字将不会被接受的。当连字体由阿拉伯字符构成时,这些图形的甚至比英文中改变的更彻底。下图阐述了两个阿拉伯字符在一起时如何组合成了单独的连体字:
4.3.2 组织文本
Ordering Text

Java 编程语言中,文本使用Unicode字符集来编码。使用Unicode字符编码的文本在内存中保存为逻辑组织(logical order)。逻辑组织是这样一种组织,在这种组织中,字符和单词可以被读取和写入。逻辑组织并不像可视组织(visual order)好样必要, 在可视组织中。相应的字形将会显示。

在特定的书写系统中,字形的可视组织称为脚本组织(script order)。例如Roman的脚本组织是从左至右的而Arabic和Hebrew的却是从右至左的。

某些书写系统除脚本组织外还有其他的一文本行上组织字形和单词的规则。例如,Arabic 和 Hebrew数字是从左到右的,尽管字母是从右到左排列。(这也就是说即使没有嵌入英语文本,Arabic和Hebrew也是真正双向的。)

一个书写系统的可视组织就算在多种语言混合的情况下也必须是能保持的。就像下图所示,在一个英文句子中购入了Arabic段落。



说明:在下面和以后的示例中,Arcbic和Hebrew文本用大小字母表示,空格部分用下划线表示。每个示例包含两个部分:存储于内存中的字符的表示(字符以逻辑组织方式),急跟着是这些字符如何表示(字符以可视组织形式)。字符下面的数字指出了插入的偏移量。

即使它们出现在英文句子中,Arabic字母也将以Arabic脚本排列:从右向左。因为italicized Arabic单词逻辑上处于纯文本后面,所以它的实际显示处于纯文本左边。

当一行中即有从左到右又有从右向左的显示。那么它的基线方向就变得有意义了。基线方向是主流书写系统上的脚本的方向。例如:如果文本中主要是英语,其中嵌入了部分Arabic,那么基线方向就是从左向右的;如果文本主要是Arabic,其中嵌入了部分英文,那么基线方向就是从右向左的。

基线方向决定了部分文本常见的显示顺序。在上面的示例中,基线是从左向右的。上面的例子中有三个方向线:处于开始位置的英语文本是从左向右的,Arabic是从右向左的,最后的句号则又是从左向右。

图形也经常嵌入到文本流中。从他们如果决定文本流以其自动换行上来说,它们更像是字形。这些行中的图形也需要使用双向布局法则来定位以使它们在字符流中恰当位置显示。

更多关于字形在同一行中的布局,请参考"description of the Bidirectional Algorithm in The Unicode Standard".

4.3.3 测量、定位文本
Measuring and Positioning Text

除非你使用单通道(monospace)字体,不同字体中的字符具有不同的宽度。这意味着所有的文本的定位及测量必须考虑其所用到的字符,而不仅仅是用到了多少字符。例如,在均衡字体中,为了右对齐一行,你不能简单使用具体的空格来定位文本。为对齐到某一列,你需要知道每一列具体的宽度,然后就可以做相应的调整。

文本通常会以多种字体和样式显示,比如:黑体或斜体。在这种情况下,即使相同的字体可以具有不同的开关和宽度,这取决于它的样式。为能恰当的定位、测量和渲染文本,你需要了解每个字体和应用到该字体的样式。幸运的是TextLayout替你完成了这些。

为了能在像Hebrew和Arabic等语言中正确显示文本,每个单独的字符都需要在相近的字符环境中测量和定位。因为字符的开关和位置可能因上下文而改变,如果不考虑上下文环境来测量和定位文本可能会产生意想不到的结果。

4.3.4 支持文本操作
Supporting Text Manipulation

为了允许用户编辑显示的文本,你要能够:
(1) 当用户进入文本时,显示一个补字号,用于指示新字符应该插入的位置;
(2) 当用户输入时,移动补字号和插入点;
(3) 检测用户选中的文本;
(4) 使选中的文本加亮。

4.3.4.1 显示补字号
Displaying Carets

在可编辑的文本中,补字号是用来图形化的表示当前的插入点的,也就是文本中新的字符将被插入的位置。典型的补字号是两个字形之间闪动的竖线。新的字符将被插入并显示在补字号的位置。

计算补字符的位置可能很复杂,尤其是在双向文本中。插入偏移量在边界方向上可能有两种补字号的位置,因为相当于字符偏移位置的两个字形并不一定是彼此相邻的。如下图所示,补字号显示为方括号来指示补字号所对应的位置:



在"_"后面和"A"前面对应8个字符的偏移量。如果用户输入一个Arabic字符,它的字形将显示在A的右面(在Arabic的文本方向中,也算是前面);如果用户输入一个英文字符,它的字形将显示在"_"右端(在英语文本方向中,也算是后面)。

为了处理这种情况,一些系统显示双重补字号,一个强(首选)补字号和弱(次选)补字号。强补字号指示将显示在文本的方向和基线方向相同的方向位置。弱补字号将显示字符的方向和文本基线方向相反的位置上。TextLayout自动支持二重补字号;JTextComponent不支持。

当你处理双向文本时,在用一个字符偏移量来处理补字号位置之前,你不能增加字形的宽度。如果你增加宽度的话,补字号将会绘制在错误的位置。如下图所示:



为了使补字号恰当的定位,相对左偏移量来说字形的宽度需要增加,并把当前的上下文考虑进来。除非把上下文考虑进来,字形度量将没必要匹配这些显示。(上下文能影响哪种字形将被使用)。

4.3.4.2 移动补字号
Moving Carets

所有的文本编辑器允许用户通过方向键移动补字号(光标)。用户期望光标的方向依照按下的方向键的方向。在从左至右的文本中,移动插入偏移量是简单的:按一下右键头,插入位置右移一位,同理按一下左键头,插入位置向左移一位。在双向文本或具有连体字的文本中,按下键头时将可能导致在方向边界位置跳过若干字形并并当按下不同的方向时,将在相反的方向上移动。

如果想在双向文本中平稳的移动补写号,你需要考虑文本的当前处理的文本的方向。当你按下向右方向键时,不能简单的增加偏移位置;当你按下向左方向键时,不能简单的减少插入偏移位置。如果当前的插入偏移位置处于从右向左的文本中,按下右方向键需要减少偏移位置,当按下左方向键时增加偏移位置。

在一个方向上的边界位置移动补字号更为复杂。下图说明了当在一个方向的边界时,用户按下方向键时将会发生的事情。当向右移动时,在文本中先后步入了三个位置,相应的显示在下图中的7、19、18。




某些字形之间是绝对不允许有补字号的;相反,补字符移动时应该把这些字开当作一个独自的字符。例如:在o和一个元音字符之间绝不允许有补字符,当他们被不同独自的字符所表示时。

TextLayout提供了方法(getNextRightHit 和 getNextLeftHit),使你能够简单平稳的在双向文本中移动补字符。

注:补字号也许可以翻译为光标。

4.3.4.3 冲突检测
Hit Testing

通常,设置空间的位置需要转换成文本偏移量。例如:当用户在可选择的文本上点击时,鼠标的位置被转换成一个文本偏移量并作为被选择的边界。逻辑上,这和布置一个补字符相反。

当你在处理双向文本时,一个在显示器上可见的位置可能对应着源文本中两个不同的偏移量。请参见下图:



因为每个独自的可见的位置能够对应两个不同的偏移,冲突检测双方向文本就不只是测量直到正确位置的字形的宽度