跳转到主要内容

文本和字体

文本和字体是新式图形用户界面的一个十分重要的方面。 必须能够以应用支持的所有语言显示高质量抗锯齿文本。

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
文本转换器的输出目录为generated/texts/。

文本转换器将文本数据库中的所有指定文本转换为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 可以与翻译工具共享,请参见下面的示例。

Excel电子表格 - 空白的翻译

Note
  • 语言必须添加在TouchGFX设计器中,而不是Excel电子表格中。
  • 排版、对齐和方向必须在TouchGFX设计器(而不是Excel电子表格)中设置。
  • 只有包含翻译的单元格才会解锁,以便在Excel电子表格中进行编辑。
  • TouchGFX设计器中对应的文本视图。

    文本视图 - 空白的翻译

    当翻译完成并返回给开发人员时,可以将它们导入文本数据库。

    Excel电子表格 - 更新后的翻译

    如需导入所有语言:

    $ 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
    对于字形位图分布格式字体(.bdf),并不能渲染字体的所有字号。 如果字体排印纸中的给定字号与给定字体不匹配,字体转换实用工具将报告支持的字号。 将字体排印纸中的字号更新为支持的字号之一,即可解决问题。

    只需将字体放在assets/fonts/文件夹中,TouchGFX Designer就可以引用该字体(如果在TouchGFX Designer运行时添加字体,必须重启软件才能更新可用字体)

    在TouchGFX Designer中,还可以使用Windows操作系统中安装的字体,选择这些字体中的任何字体,它们就会被自动添加到assets/fonts/文件夹

    字体转换器使用提供的字体中的字距调整信息进行字距调整。

    Note
  • 使用TouchGFX并不以任何形式提供任何TrueType、OpenType或Bitmap字体的商业使用许可。
  • 字体转换器的输出目录为generated/fonts/。
  • 字符存储空间优化

    TouchGFX为减少存储空间消耗而进行了优化。 通过分析对特定字体排印使用的字符,将生成的字符(内部C++格式)数量最大限度压缩至应用实际使用的字符。

    另外,通过在文本配置中启用重新映射文本的选项,压缩使用常用后缀的文本,从而优化文本存储空间消耗量。

    通配符

    TouchGFX可将动态值作为文本的一部分来使用。 这可以通过在文本中使用通配符来实现。 按给定格式<*>指定通配符,其中的*表示不会包含在结果文本中的可选辅助文本。 一个文本中可以有至多2个通配符。

    给定文本的所有翻译文件必须包含相同数量的通配符。 通配符值在运行时被插入到C++代码中。

    通配符使用示例:温度为 <insert_temperature>°

    要注意的一个细节是,由于字符存储空间优化(参见上一节),只为特定字体排印生成了采用此字体排印的文本中使用的字符。 为强制字体生成器包含特定字符,您可以对每种字体排印使用“通配符字符”和“字符范围”。

    像下面这样使用反斜杠记号可以避免通配符格式<*>\<not a wildcard\>. 这会导致应用中使用原义文本 “<not a wildcard>” 。

    在TouchGFX Designer中使用通配符

    在TouchGFX Designer中,可以将通配符添加到常规TextArea。 现在,尽管TouchGFX中生成代码的方式并无变化,但有效地让TextArea控件覆盖了之前被TextAreaWithOneWildcard/TextAreaWithTwoWildcards控件覆盖的功能。

    在TouchGFX 设计器中,只需单击“+”按钮为所选文本区域的属性添加通配符,即可将通配符添加到文本区域。 点击相应的“-”按钮以删除通配符。 一个熟悉的示例是将温度读数添加到TextArea,可显示为温度为 °。 这种情况下可能是室外温度读数。 下面我们要插入一个通配符,不仅显示静态数值,还将根据温度读数进行更新。 通配符会被添加到文本中插入点光标的当前位置:

    将通配符添加到Text Area控件

    现在,属性中的文本将显示“温度为<value>°”,而画布上的文本显示“温度为°:”

    TouchGFX Designer中带通配符的Text Area控件

    为了设置特定的通配符,您可以点击相应的“通配符”按钮(本例中为通配符1),就可以编辑刚才添加的通配符。

    在这里,您可以选择如何更新通配符。 要么通过预定义资源文本,要么通过动态运行时间创建的文本。 在两种情况下,都可以在运行时间更新文本。 要使用自动生成的文本,请点击“+”创建自动生成文本或选择现有文本。 如需要动态文本,请使用通配符缓冲区。 这样的缓冲区可通过选中通配符缓冲区复选框来创建。 在这种情况下,还需要指定缓冲区大小(字符数)。 如果想要高效地利用存储空间,需使指定大小尽可能接近实际需要的文本大小。 记住,为字符串结束符(“\0”)增加一个额外空格。

    在TouchGFX 设计器中将自动生成的文本添加到通配符

    另外,还可以为通配符设置初始值,这样可以看到包含温度读数的TextArea的最终外观:

    TouchGFX Designer中的通配符设置

    在用户代码中使用通配符

    还可通过用户代码添加和更新通配符,如下面的代码示例所示,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的文本视图中进行设置。

    设置TextArea的正确宽度和高度

    TextArea能够根据目前选择的文本调整其宽度和高度。 这是通过调用TextArea::resizeToCurrentText()方法来完成的。

    Note
    `resizeToCurrentText()`会被自动调用,前提是在实例化具有新TypedText的TextArea时没有设置宽度和高度。

    在使用中心/右对齐文本时,通常不希望调整宽度和高度,因为文本需要在固定区域内实现中心/右对齐。 在这种情况下,可以手动设置宽度和高度。 这可以通过调用TextArea::setPosition(x, y, width, height)TextArea::setWidth(width)TextArea::setHeight(height)来完成。

    如果宽度和/或高度过小,无法容纳文本,将按照区域剪切文本,如下图所示。

    被 TextArea边界裁剪的文本

    为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
    由于setBaselineY依赖于字体,TextArea需在调用setBaselineY之前设置其TypedText。 另外还要注意,如果将TextAreas TypedText修改为采用其他字体或字号,则需要再次调用setBaselineY。

    长文本行的自动换行

    TextArea有时需要包含极长的文本。 By default, such text is simply written as a single line and all text that does not fit inside the TextArea is simply cut off. If instead the text should be wrapped between words and re-flowed to fill several lines, simply set the "wide text action" by calling:

    myTextArea.setWideTextAction(WIDE_TEXT_WORDWRAP); // Default is WIDE_TEXT_NONE

    TouchGFX can also add a special character (e.g. ) when there is not enough space available to print the whole string. This is called an ellipsis character.

    可用宽文本操作

    A number of different wide text actions are available:

    • WIDE_TEXT_NONE: 只需从超出TextArea宽度的任何字符的中间切割文本,无需其他操作。 This is the default action.
    • WIDE_TEXT_WORDWRAP: Wrap to the next line between words, do not add an ellipsis".
    • WIDE_TEXT_WORDWRAP_ELLIPSIS: Wrap to the next line between words, put ellipsis anywhere "Very long t...".
    • WIDE_TEXT_WORDWRAP_ELLIPSIS_AFTER_SPACE: Wrap to next line between words, ellipsis anywhere after space "Very long ...".
    • WIDE_TEXT_CHARWRAP: Wrap to next line between any two characters, no ellipsis.
    • WIDE_TEXT_CHARWRAP_ELLIPSIS: Wrap to next line between any two characters, ellipsis anywhere, as used in Chinese.
    • WIDE_TEXT_CHARWRAP_DOUBLE_ELLIPSIS: Wrap between any two characters, double ellipsis anywhere, as used in Chinese.

    这可能会使TextArea需要更多垂直空间。 This can either be achieved by increasing the height of the TextArea in the Designer or it can be done in user code as follows:

    myTextArea.setWidth(200);
    myTextArea.resizeHeightToCurrentText(); // Will set height by wrapping text at 200px long lines
    myTextArea.invalidate();

    如果您准备缩小文本区的尺寸,记得在调整 myTextArea 尺寸之前调用myTextArea.invalidate()。 如果没有,由于原文本区未被更小的新文本区覆盖,因此您会看到它的一部分。

    Setting the ellipsis character

    If you select a wide text action different from WIDE_TEXT_NONE and you want to see the ellipsis character you must also include the ellipsis character in the font, by specifying the chosen character or the Unicode number in the Designer:

    Setting the ellipsis character for a font

    The Unicode 0x2026 is the standard horizontal ellipsis.

    切换语言

    TouchGFX支持多语言界面。 可以更改界面当前使用的语言,方法是调用静态函数Texts::setLanguage:

    Texts::setLanguage(GB);

    GB位于LANGUAGES枚举(位于TextKeysAndLanguages.hpp中)中,如“文本转换器”一节中的示例所示。

    此次调用后,使所有显示文本的控件无效(或简单地使整个屏幕无效),它们将以新选择的语言显示文本。

    TouchGFX Designer中

    您可以在不同语言之间切换,以便测试所有翻译文件。 可从配置视图的常规部分执行此操作。 这里只需更改应用的启动语言,方法是更改选中语言