4. 界面基础元素:屏幕与容器,以及常用控件

好,我们正式开始动手了。这一章我会带你认识 TouchGFX 里最基础的几个界面元素——屏幕(Screen)、容器(Container),以及三个最常用的控件:Box、Image 和 Text。

说白了,你后面做的所有界面,都是这些东西拼起来的。就像搭积木,先认识每块积木长什么样,才知道怎么搭。

本章核心:理解 Screen 和 Container 的层级关系,掌握 Box、Image、Text 三个控件的创建与配置方法。

第4章 知识结构:界面基础元素 界面基础元素 Screen(屏幕) Container(容器) Box Image Text Box Image Text Screen 是顶层容器,一个界面只有一个 Screen Container 是子容器,用于分组管理控件

4.1 屏幕(Screen)—— 界面的根

每个 TouchGFX 界面,最顶层就是一个 Screen。你可以把它理解成一张画布,所有控件都画在这张画布上。

我刚开始接触 TouchGFX 时,犯过一个低级错误——试图在一个 Screen 里再放一个 Screen。结果编译报错,查了半天文档才明白:Screen 是唯一的顶层容器,不能嵌套。

我的习惯:在 TouchGFX Designer 里新建项目后,先重命名默认的 Screen。比如叫 MainScreen 或 HomeScreen,别留着 Screen1、Screen2 这种名字。项目大了你就知道好处了。

Screen 的生命周期由框架管理。切换界面时,TouchGFX 会销毁当前 Screen,创建新的 Screen。所以,全局变量或状态不要放在 Screen 类里,否则一切换就丢了。我吃过这个亏,调试了一下午才发现是变量被重置了。

4.2 容器(Container)—— 控件的收纳盒

Container 是什么?说白了就是一个可以装其他控件的控件。它本身不显示任何东西,但你可以用它来分组管理一组控件。

举个例子:你做了一个仪表盘,上面有 5 个温度显示、3 个转速表。如果把它们都直接放在 Screen 上,想整体移动或隐藏时,你得一个一个操作。但如果把它们先放进一个 Container,你只需要操作 Container 一个对象就够了。

特性 Screen Container
层级 顶层,不能嵌套 子层,可以嵌套多层
生命周期 由框架管理 由父容器或 Screen 管理
可见性 始终可见(除非被覆盖) 可单独设置 visible
典型用途 承载整个界面 分组、动画、复用

注意:Container 的坐标是相对于父容器的。如果你把 Container 放在 (100, 50),里面的子控件坐标 (0, 0) 实际对应屏幕的 (100, 50)。我曾经在嵌套三层 Container 后,找子控件的位置找了半天……嗯,画个坐标图就清楚了。

4.3 Box 控件——最简单的色块

Box 就是纯色矩形。没有边框、没有圆角、没有渐变——就是一个色块。

你可能会问:这么简单的东西有什么用?

用处大了。背景色、分割线、进度条的底色、按钮的填充……很多地方都需要纯色块。而且 Box 的渲染开销极低,适合做大量重复的背景元素。

在 TouchGFX Designer 里拖一个 Box 出来,你只需要设置:

  • 位置和大小:x, y, width, height
  • 颜色:24 位 RGB,比如 0x2E86C1
  • 透明度:0(全透明)到 255(不透明)

代码里创建 Box 也很简单:

// 创建一个蓝色 Box,覆盖整个屏幕作为背景
Box background;
background.setPosition(0, 0, 480, 272);
background.setColor(0x2E86C1);
background.setAlpha(200);  // 半透明效果

避坑指南:我曾经用 Box 做按钮背景,但忘了设置 setTouchable(true)。结果按钮点不了,因为 Box 默认不接收触摸事件。如果你需要 Box 响应点击,记得加上这一行。

4.4 Image 控件——图片显示

Image 用来显示图片。TouchGFX 支持 PNG、BMP、JPG 等格式,但最终都会转换成内部格式。

使用 Image 的步骤:

  1. 准备图片资源:放在项目的 assets/images 目录下
  2. 在 Designer 里添加:从 Image 列表里选择你导入的图片
  3. 设置位置:x, y 坐标
  4. (可选)设置缩放:setScalingAlgorithm 选择缩放算法

代码示例:

// 显示一张图标
Image icon;
icon.setXY(100, 50);
icon.setBitmap(Bitmap(BITMAP_MY_ICON_ID));  // 图片 ID 由 TouchGFX 自动生成

重要:TouchGFX 的图片是直接内存映射的,不经过文件系统。所以图片大小直接影响 RAM/Flash 占用。一张 480x272 的 24 位图,未经压缩就是 480×272×3 ≈ 391 KB。如果你的 MCU Flash 只有 1MB,放两张图就满了。我建议:能用纯色 Box 的地方就别用图片,能用 8 位索引色的就别用 24 位真彩色。

4.5 Text 控件——显示文字

Text 控件用来显示字符串。它支持多种字体、颜色、对齐方式。

配置 Text 需要先设置字体(Typography)。在 TouchGFX Designer 的 Text 面板里:

  • 选择或新建一个 Typography(字体名称、大小、粗细)
  • 设置文字颜色
  • 设置对齐方式:左对齐、居中、右对齐
  • 输入默认文本(可以留空,运行时动态设置)

代码里动态更新文本:

// 假设界面上有一个 Text 控件叫 textLabel
Unicode::snprintf(textLabelBuffer, TEXT_LABEL_SIZE, "温度: %d°C", temperature);
textLabel.invalidate();  // 刷新显示

注意缓冲区大小:Text 控件内部有一个固定大小的缓冲区。如果你写入的字符串超过缓冲区长度,会截断甚至导致内存越界。我建议:缓冲区大小 = 最大可能字符数 × 2 + 4,给 Unicode 字符留足空间。

另外,中文字体需要额外处理。TouchGFX 默认字体只包含 ASCII 字符。要显示中文,你需要:

  1. 在 assets/fonts 目录下放置中文字体文件(如 simhei.ttf)
  2. 在 TouchGFX/target/generated/FontCache.cpp 中配置需要包含的汉字范围
  3. 重新生成代码

嗯,这一步有点麻烦。我一般先列好所有要用到的汉字,生成一个精简字体文件,能省不少 Flash 空间。

4.6 实战:组合使用

来,我们做一个简单的界面:一个带背景色、图标和文字的卡片。

// 在 Screen 的 setupScreen() 中
// 1. 背景 Box
backgroundBox.setPosition(0, 0, 480, 272);
backgroundBox.setColor(0xF0F8FF);
add(backgroundBox);

// 2. 卡片容器
cardContainer.setPosition(40, 60, 400, 150);
cardContainer.setVisible(true);
add(cardContainer);

// 3. 卡片背景
cardBg.setPosition(0, 0, 400, 150);
cardBg.setColor(0xFFFFFF);
cardBg.setAlpha(200);
cardContainer.add(cardBg);

// 4. 图标
iconImage.setXY(20, 25);
iconImage.setBitmap(Bitmap(BITMAP_TEMP_ICON_ID));
cardContainer.add(iconImage);

// 5. 文字
titleText.setPosition(80, 30, 300, 30);
titleText.setTypedText(TypedText(T_TITLE));
titleText.setColor(0x2C3E50);
Unicode::snprintf(titleTextBuffer, TITLE_SIZE, "当前温度");
cardContainer.add(titleText);

valueText.setPosition(80, 70, 300, 50);
valueText.setTypedText(TypedText(T_VALUE));
valueText.setColor(0xE74C3C);
Unicode::snprintf(valueTextBuffer, VALUE_SIZE, "25.5°C");
cardContainer.add(valueText);

你看,一个简单的卡片就做好了。背景是 Box,图标是 Image,文字是 Text,它们都放在 Container 里。想整体移动卡片?改 cardContainer.setXY() 就行。

我的习惯:每个功能模块都用一个 Container 包起来。比如导航栏一个 Container,内容区一个 Container,底部状态栏一个 Container。这样后期维护时,找控件、改布局都特别快。

4.7 本章小结

这一章我们认识了 TouchGFX 的五个基础元素:

  • Screen:界面的根,一个界面只有一个
  • Container:控件的收纳盒,用于分组管理
  • Box:纯色块,轻量级背景元素
  • Image:图片显示,注意内存占用
  • Text:文字显示,注意缓冲区大小和中文支持