文本和字体
文本和字体是新式图形用户界面的一个十分重要的方面。 必须能够以应用支持的所有语言显示高质量抗锯齿文本。
TouchGFX支持通过TouchGFX Designer的文本视图创建和修改文本和字体排印。 TouchGFX设计器将文本和字体排印配置输出到数据库(位于assets/texts/texts.xml
)。 将此数据库与字体文件一起输入字体和文本转换器工具,输出生成的TouchGFX可渲染的C++代码文件。
本文介绍文本和字体转换器工具,并说明如何通过代码和TouchGFX Designer使用在应用中生成的文本。
文本和字体排印
TouchGFX应用中的文本和字体排印存储在assets/texts/texts.xml
数据库中。 该数据库包含应用中使用的带有翻译的文本和排版。 此数据库通常被称为“文本数据库”。
文本和排版可以在TouchGFX设计器中通过文本视图进行编辑,这使编辑变得简单和方便。
但是,可以在texts.xml中直接编辑排版和文本;为了辅助编辑,为validation assets/text /text .xsd
提供了一个XML模式。 许多已知的文本编辑器都通过XML插件支持XML模式验证,例如VS code、notepad++、或Emacs、Visual Studio。 通常建议在编辑文本和排版时使用TouchGFX设计器,以避免排版的不一致和翻译缺失,这是XML模式无法验证的。
为了支持在TouchGFX设计器之外进行文本翻译(例如使用外部翻译工具进行翻译),文本转换器现在配有新的独立式工具,允许从文本数据库导出文本翻译到Excel电子表格。 该Excel表格可以与外部翻译工具共享。 当翻译更新后,可以使用相同的工具将Excel电子表格重新导入文本数据库。 详细了解翻译相关事宜。
Further reading
文本转换器
文本转换器是将文本数据库中的文本信息转换为TouchGFX应用使用的内部C++格式的工具。 该工具是构建工具链不可或缺的一部分,将在构建应用时自动执行。 只有在文本数据库中的翻译或文本属性被修改或添加了新的文本或翻译之后,文本转换器才会生成新的C++代码。
Note
文本转换器将文本数据库中的所有指定文本转换为TouchGFX使用的文本格式。 格式被封装成名为TypedText
的对象。 TouchGFX中的TypedText
是文本内容本身与文本字体排印的组合实体。 字体排印包含文本的字体和字号,以及字体字形抗锯齿时使用的每像素位数(bpp)。
文本转换器生成名为generated/texts/include/texts/TextKeysAndLanguages.hpp
的文件。 此文件包含引用文本数据库中所有文本的枚举TEXTS
。
请注意,枚举中的所有条目均生成自文本数据库每个文本节点中规定的ID,但具有前置的T_并转换成大写字母。 应用中使用这些枚举值初始化TypedText。
TextKeysAndLanguages.hpp
还包含枚举LANGUAGES
,它指定文本数据库中现有的所有语言。 命名与文本数据库中的语言列相同。
generated/texts/include/texts/TextKeysAndLanguages.hpp
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#ifndef TEXT_KEYS_AND_LANGUAGES_HPP
#define TEXT_KEYS_AND_LANGUAGES_HPP
typedef enum {
GB,
DE,
NUMBER_OF_LANGUAGES
} LANGUAGES;
typedef enum {
T_TEMPERATURE_READOUT,
T_TEMPERATURE_HEADLINE,
NUMBER_OF_TEXT_KEYS
} TEXTS;
#endif /* TEXT_KEYS_AND_LANGUAGES_HPP */
翻译
本节简要介绍导出和导入文本翻译时的工作流程。
考虑这样一个场景:开发人员创建了一个包含文本的应用程序,这些文本需要翻译成多种不同的语言。 开发人员使用外部翻译工具,需要导出文本,然后输入到翻译工具。
为了导出文本,开发人员使用位于touchgfx/framework/tools/textconvert/translations.rb
的新工具。 该工具可以在TouchGFX Environment中运行。 运行不带任何参数的工具,将打印以下帮助文本:
$ translations.rb
使用Excel等工具导出和导入文本数据库,以进行翻译
用法:translations.rb {export|import} assets/texts/texts.xml translations.xlsx [language]*
导出:将创建“translations.xlsx” ,方法是
从给定的assets/texts/texts.xml提取所有语言的文本
导入: 将文本翻译从“translations.xlsx” 合并到给定的assets/texts/texts.xml。 只导入实际的文本,不会导入对齐和文本方向。
如果未指定语言,将处理所有语言,否则只导入/导出指定的语言。
如需导出所有语言:
$ translations.rb export assets/texts/texts.xml translations.xlsx
如需导出指定语言,例如英语、法语和阿拉伯语:
$ translations.rb export assets/texts/texts.xml translations.xlsx English French Arabic
现在,Excel电子表格 touchgfx/framework/tools/textconvert/translations.xlsx
可以与翻译工具共享,请参见下面的示例。
Note
TouchGFX设计器中对应的文本视图。
当翻译完成并返回给开发人员时,可以将它们导入文本数据库。
如需导入所有语言:
$ translations.rb import assets/texts/texts.xml translations.xlsx
如需导入指定语言,例如法语和阿拉伯语:
$ translations.rb import assets/texts/texts.xml translations.xlsx French Arabic
现在,文本数据库中的翻译已经更新。
建议
导出文本用于翻译,然后再次导入,应该在文本数据库的同一基线上进行,这样可以避免导入过程中的潜在冲突。 如果你使用版本控制系统(例如Git),建议在导出之前创建一个分支,然后在导出完成后用文本翻译更新该分支,最后将该分支合并回主枝。
下图显示了一个示例,示例中将阿拉伯语和法语翻译导入到翻译分支,然后合并回主枝。 示例还展示了:在翻译分支上进行工作的同时,对主枝上的文本数据库进行更改时应该小心,因为会出现合并冲突。
合并冲突会在这些情况下出现:
- 删除主枝上文本数据库中的文本ID时
- 在主枝上的文本数据库中添加文本ID时
- 对主枝上文本数据库中的文本ID进行重命名时
文本转换器
文本转换器是将字体文件中的信息与文本数据库中的信息进行组合并生成应用需要的字符的工具。 输出格式是TouchGFX应用使用的内部C++格式。 该工具是构建工具链不可或缺的一部分,将在构建模拟器时自动执行。
文本转换器接受
- TrueType (.ttf)
- OpenType (.otf)
- Glyph Bitmap Distribution Format (.bdf).
Note
只需将字体放在assets/fonts/
文件夹中,TouchGFX Designer就可以引用该字体(如果在TouchGFX Designer运行时添加字体,必须重启软件才能更新可用字体)。
在TouchGFX Designer中,还可以使用Windows操作系统中安装的字体,选择这些字体中的任何字体,它们就会被自动添加到assets/fonts/
文件夹
字体转换器使用提供的字体中的字距调整信息进行字距调整。
Note
字符存储空间优化
TouchGFX为减少存储空间消耗而进行了优化。 通过分析对特定字体排印使用的字符,将生成的字符(内部C++格式)数量最大限度压缩至应用实际使用的字符。
另外,通过在文本配置中启用重新映射文本的选项,压缩使用常用后缀的文本,从而优化文本存储空间消耗量。
通配符
TouchGFX可将动态值作为文本的一部分来使用。 这可以通过在文本中使用通配符来实现。 按给定格式<*>
指定通配符,其中的*表示不会包含在结果文本中的可选辅助文本。 一个文本中可以有至多2个通配符。
给定文本的所有翻译文件必须包含相同数量的通配符。 通配符值在运行时被插入到C++代码中。
通配符使用示例:温度为 <insert_temperature>°
要注意的一个细节是,由于字符存储空间优化(参见上一节),只为特定字体排印生成了采用此字体排印的文本中使用的字符。 为强制字体生成器包含特定字符,您可以对每种字体排印使用“通配符字符”和“字符范围”。
像下面这样使用反斜杠记号可以避免通配符格式<*>
:\<not a wildcard\>. 这会导致应用中使用原义文本 “<not a wildcard>” 。
在TouchGFX Designer中使用通配符
在TouchGFX Designer中,可以将通配符添加到常规TextArea。 现在,尽管TouchGFX中生成代码的方式并无变化,但有效地让TextArea控件覆盖了之前被TextAreaWithOneWildcard/TextAreaWithTwoWildcards控件覆盖的功能。
在TouchGFX 设计器中,只需单击“+”按钮为所选文本区域的属性添加通配符,即可将通配符添加到文本区域。 点击相应的“-”按钮以删除通配符。 一个熟悉的示例是将温度读数添加到TextArea,可显示为温度为 °。 这种情况下可能是室外温度读数。 下面我们要插入一个通配符,不仅显示静态数值,还将根据温度读数进行更新。 通配符会被添加到文本中插入点光标的当前位置:
现在,属性中的文本将显示“温度为<value>°”,而画布上的文本显示“温度为°:”
为了设置特定的通配符,您可以点击相应的“通配符”按钮(本例中为通配符1),就可以编辑刚才添加的通配符。
在这里,您可以选择如何更新通配符。 要么通过预定义资源文本,要么通过动态运行时间创建的文本。 在两种情况下,都可以在运行时间更新文本。 要使用自动生成的文本,请点击“+”创建自动生成文本或选择现有文本。 如需要动态文本,请使用通配符缓冲区。 这样的缓冲区可通过选中通配符缓冲区复选框来创建。 在这种情况下,还需要指定缓冲区大小(字符数)。 如果想要高效地利用存储空间,需使指定大小尽可能接近实际需要的文本大小。 记住,为字符串结束符(“\0”)增加一个额外空格。
另外,还可以为通配符设置初始值,这样可以看到包含温度读数的TextArea的最终外观:
在用户代码中使用通配符
还可通过用户代码添加和更新通配符,如下面的代码示例所示,Unicode::UnicodeChar
阵列在用户代码中进行管理和更新。
gui/include/gui/some_screen/SomeView.hpp
#include <touchgfx/widgets/TextAreaWithWildcard.hpp>
...
class SomeView : public View<SomePresenter>
{
TextAreaWithOneWildcard txt;
Unicode::UnicodeChar txtBuffer[10];
}
gui/src/some_screen/SomeView.cpp
#include <texts/TextKeysAndLanguages.hpp>
void SomeView::setupScreen()
{
txt.setTypedText(TypedText(T_TEMPERATURE_READOUT));
txt.setXY(10, 20);
txt.setWildcard(txtBuffer);
add(txt);
updateTxt(5);
}
void SomeView::updateTxt(int newValue)
{
Unicode::snprintf(txtBuffer, 10, "%d", newValue);
txt.invalidate();
}
文本放置
对于所有TouchGFX控件,通过指定位置(X和Y)和尺寸(宽和高)将TextArea放置到屏幕上。 可以在TouchGFX Designer的控件属性中轻松做到这一点,但是与TouchGFX渲染文本相比,TouchGFX Designer中的文本渲染并非总是100%准确。
本节还描述了在处理文本时要注意的更多细节和可能性。
对齐
按照为文本数据库中选中文本条目指定的对齐方式对齐TextArea中的文本。 文本对齐是就TextArea的区域而言。 在下面的屏幕截图中,TextArea的区域高亮显示为蓝色。
这些设置可以在TouchGFX Designer的文本视图中进行设置。
Font size
As we saw above TouchGFX only includes the characters from a font that are needed by the application. Based on this selection TouchGFX calculates the font height and placement (called the baseline) of the characters. The font height is the height in pixels of a line of text using the font. The baseline is the placement of the letters on that line.
These attributes are available through the Font class if needed at runtime:
The size of the individual characters (glyphs) can be found using the methods on the GlyphNode struct:
The height of a glyph is the number of rows of pixels used when drawing the glyph. The top is the number of lines above the baseline the glyph should be drawn. Note that, the glyph may stay above the base (as '^') or go below the baseline (as 'g').
Here is an example where we have used Verdana in size 100px in the TouchGFX Designer. The application only writes the text "Ac" on the screen:
The green line shows the position of the baseline. The font height is 101 pixels. The baseline position is 100. The size of the 'A' is 73. The top is also 73. The 'A' is therefore resting on the baseline. The height of 'c' is 57, and the top is 56. The 'c' therefore draws one line further down than the 'A'. These values are part of the Verdana font design.
Here is another example, where we have used the same font, but the application now write the text "Acg" on the screen:
The inclusion of the 'g' in the application changes the font. The font height is now 121, but the baseline position is still 100. The line is thus expanded to make room for the 'g' (hangs below the line), but the 'A' and 'c' are positioned vertically as before. The height of 'g' is 77, but the top is only 56, so 21 lines of pixels falls below the baseline.
We have thus seen that the height of a font in TouchGFX is dependent on the included letters. The individual characters are positioned relative to the baseline of the font.
设置TextArea的正确宽度和高度
TextArea能够根据目前选择的文本调整其宽度和高度。 这是通过调用TextArea::resizeToCurrentText()
方法来完成的。
Note
在使用中心/右对齐文本时,通常不希望调整宽度和高度,因为文本需要在固定区域内实现中心/右对齐。 在这种情况下,可以手动设置宽度和高度。 这可以通过调用TextArea::setPosition(x, y, width, height)
、TextArea::setWidth(width)
和TextArea::setHeight(height)
来完成。
如果宽度和/或高度过小,无法容纳文本,将按照区域剪切文本,如下图所示。
为TextArea设置正确的X和Y值
为了将TextArea放在正确的X和Y位置,需注意使用的字体的字符上方会有一些额外的间隔,可以容纳大字符。 由于不知道文本上方的具体间隔,使得根据左上角的Y位置放置TextArea变得有点困难。 放置文本的一种方式是指定您认为它应当处于的位置,然后通过在模拟器中检查放置效果来进行微调。 这通常是一项十分简单的任务,但如果之后更改字体或字号,则需要重新执行。
一种更稳健的方式是使用文本基线。 基线是一条线,大多数字母“坐”在基线上,而下行字母(像p和j这样的字符)会延伸到基线之下。
为了设置文本基线,可使用TextArea::setBaselineY(y)
或TextArea::setXBaselineY(x, y)
。 对于这些方法,不指定TextArea的左上角,而是指定第一个文本行的基线。 这会考虑字号和间距,并相应地设置TextArea的Y位置。
由于通过TouchGFX Designer画布可以轻松地放置TextArea控件,因此TouchGFX Designer中没有基线功能,只能在用户代码中使用。
Note
长文本行的自动换行
Sometimes a TextArea contains a text which is very long. 默认情况下,只需将此类文本写成一行,并直接将超出TextArea的所有文本剪切掉。 If instead the text should be automatically wrapped at spaces and re-flowed to fill several lines, simply call:
myTextArea.setWideTextAction(WIDE_TEXT_WORDWRAP); // Default is WIDE_TEXT_NONE
当没有足够的空间打印整个字符串时,TouchGFX还可以添加一个特殊字符(例如…)。 这称为省略号字符。
可用宽文本操作
WIDE_TEXT_NONE
: No automatic, simply cut the text in the middle of any character that extends beyond the width of the TextArea.WIDE_TEXT_WORDWRAP
: Wrap between words, no ellipsis character.WIDE_TEXT_WORDWRAP_ELLIPSIS
: Wrap between words, insert ellipsis character after last visible letter, e.g.: "Very long t...".WIDE_TEXT_WORDWRAP_ELLIPSIS_AFTER_SPACE
: Wrap between words, ellipsis character only after space "Very long ...".WIDE_TEXT_CHARWRAP
: Wrap between any two characters, no ellipsis character, as used in Chinese.WIDE_TEXT_CHARWRAP_ELLIPSIS
: Wrap between any two characters, ellipsis character after last visible letter, as used in Chinese.WIDE_TEXT_CHARWRAP_DOUBLE_ELLIPSIS
:Wrap between any two characters, double ellipsis after last visible letter, as used in Chinese.
The images below illustrate the different line wrapping modes:
Further reading
这可能会使TextArea需要更多垂直空间。 可通过增加TouchGFX Designer中TextArea的高度或在用户代码中用以下代码来实现。
myTextArea.setWideTextAction(WIDE_TEXT_WORDWRAP);
myTextArea.setWidth(200);
myTextArea.resizeHeightToCurrentText(); // Will set height by wrapping text at 200px long lines
myTextArea.invalidate();
如果您准备缩小文本区的尺寸,记得在调整 myTextArea
尺寸之前调用myTextArea.invalidate()
。 如果没有,由于原文本区未被更小的新文本区覆盖,因此您会看到它的一部分。
设置省略号
如果选择不同于WIDE_TEXT_NONE
的宽文本操作,且希望看到省略号字符,则必须在字体中包含省略号字符,方法是在Designer中指定所选字符或Unicode数字:
Unicode 0x2026是标准的水平省略号。
Manual line-breaks
You can also insert manual line-breaks in the text (ASCII / Unicode character 10). This character will cause the TextArea to change to the next line independent of the WideTextAction setting.
In XML you write the newlines as " ". For example:
<Text Id="__SingleUse_1VW7" Alignment="Left" TypographyId="Default">
<Translation Language="GB">New Text On 3 lines.</Translation>
</Text>
Which produces:
New
Text
On 3 lines.
切换语言
TouchGFX支持多语言界面。 可以更改界面当前使用的语言,方法是调用静态函数Texts::setLanguage
:
Texts::setLanguage(GB);
值GB位于LANGUAGES
枚举(位于TextKeysAndLanguages.hpp
中)中,如“文本转换器”一节中的示例所示。
此次调用后,使所有显示文本的控件无效(或简单地使整个屏幕无效),它们将以新选择的语言显示文本。
TouchGFX Designer中
您可以在不同语言之间切换,以便测试所有翻译文件。 可从配置视图的常规部分执行此操作。 这里只需更改应用的启动语言,方法是更改选中语言。