3. 第一个Hello World项目:LVGL的lv_label_create与TouchGFX的TextArea控件使用对比
说实话,学嵌入式GUI开发,最让人兴奋的就是看到屏幕上出现自己写的文字。我记得当年第一次在STM32上点亮一个“Hello World”,那种成就感,比后来调通任何复杂协议栈都强烈。
这一章,我们就来对比LVGL和TouchGFX如何实现这个经典入门程序。别看只是显示一行字,两个框架的代码结构差异,从这里就开始分道扬镳了。
3.1 LVGL:用lv_label_create创建文本
LVGL的文本控件叫Label(标签)。它的设计哲学很直接——你创建一个对象,设置它的文本,然后把它放到屏幕上。就这么简单。
先看代码:
/* LVGL - Hello World 示例 */
void lvgl_hello_world(void)
{
/* 1. 创建一个标签对象 */
lv_obj_t *label = lv_label_create(lv_scr_act());
/* 2. 设置文本内容 */
lv_label_set_text(label, "Hello World");
/* 3. 让标签自动适应文本大小 */
lv_obj_set_width(label, LV_SIZE_CONTENT);
lv_obj_set_height(label, LV_SIZE_CONTENT);
/* 4. 将标签居中显示 */
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
}
嗯,这里要注意:lv_label_create的第一个参数是父对象。lv_scr_act()返回当前活动屏幕。你想想看,LVGL里所有控件都是对象,都挂在一个对象树上。屏幕是根节点,Label是它的子节点。
我个人习惯在创建控件后,立刻设置LV_SIZE_CONTENT。为什么?因为Label默认有固定宽高,如果不设置自适应,文字可能会被截断。我在项目中遇到过好几次,调试了半天发现文字只显示了一半,就是这个原因。
lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL)让它滚动起来。
3.2 TouchGFX:用TextArea显示文本
TouchGFX的做法完全不同。它不让你在C代码里直接写字符串,而是通过一个叫“文本ID”的机制来管理所有文本。
流程是这样的:
- 在TouchGFX Designer里拖一个TextArea控件到屏幕
- 在文本资源(Texts)里定义一个文本ID,比如
T_SINGLEUSEID1 - 在代码里通过
setTypedText方法引用这个ID
生成的C++代码大概长这样:
/* TouchGFX - Hello World 示例(自动生成的代码) */
class Screen1View : public Screen1ViewBase
{
public:
Screen1View() {}
virtual ~Screen1View() {}
virtual void setupScreen()
{
/* TextArea的文本已经在Designer中设置好了 */
/* 如果需要动态修改,可以这样写: */
textArea1.setTypedText(TypedText(T_SINGLEUSEID1));
textArea1.setWildcard(textArea1Buffer);
Unicode::snprintf(textArea1Buffer, TEXTAREA1_SIZE, "Hello World");
textArea1.invalidate();
}
};
看到了吗?TouchGFX把文本定义和UI逻辑分开了。文本ID在资源文件里定义,实际字符串在运行时填充。这种做法在需要多语言支持的项目里特别有用——你只需要切换文本资源文件,不用改一行代码。
3.3 核心差异:代码结构对比
两个框架的差异,说白了就是“直接操作”和“间接管理”的区别。我整理了一张对比表,你可以直观感受一下:
| 对比维度 | LVGL | TouchGFX |
|---|---|---|
| 创建方式 | API函数直接创建 | Designer拖拽 + 代码引用 |
| 文本设置 | 运行时直接赋值字符串 | 通过文本ID间接引用 |
| 代码位置 | 全部在C源文件中 | 分散在Designer配置和C++代码中 |
| 多语言支持 | 需要自己实现切换逻辑 | 内置资源文件切换机制 |
| 运行时修改 | 直接调用lv_label_set_text |
需要调用invalidate()刷新 |
| 内存管理 | 动态分配,需关注内存碎片 | 静态分配,Designer预分配 |
你想想看,LVGL的方式更灵活,适合快速原型开发。TouchGFX的方式更规范,适合团队协作和产品化。没有绝对的好坏,关键看你的项目需求。
3.4 代码结构差异:从Hello World看框架设计
一个简单的Hello World,其实暴露了两个框架的设计哲学差异。我画了一张结构图,帮你理清思路:
从这张图可以看得很清楚:LVGL是“一条龙”式的代码结构,所有操作都在一个函数里完成。TouchGFX则是“分步走”,Designer配置和代码实现各司其职。
3.5 避坑指南:我踩过的那些坑
做嵌入式开发,不踩几个坑都不好意思说自己是老手。关于这两个框架的Hello World,我分享几个亲身经历:
- LVGL的字体问题: 我曾经在项目里直接写中文“你好世界”,结果屏幕上显示的是方框。后来才发现LVGL默认字体不包含中文字符,需要自己添加字体文件。所以,如果你用LVGL显示中文,记得先配置字体。
- TouchGFX的文本ID冲突: 有一次我在Designer里复制了一个屏幕,结果两个屏幕共用了同一个文本ID。修改一个,另一个也跟着变。排查了半天,最后发现是ID命名不规范导致的。建议给每个文本ID加上屏幕前缀,比如
T_SCREEN1_HELLO。 - 内存泄漏: LVGL的
lv_label_create会动态分配内存。如果你频繁创建和删除Label,一定要记得调用lv_obj_del释放。我见过一个同事在循环里不断创建Label,最后内存耗尽系统崩溃。
3.6 小结:选择哪个框架?
回到最初的问题:LVGL和TouchGFX,第一个Hello World项目选哪个?
我的建议是:
- 如果你追求快速上手、灵活调试,选LVGL。它的API直观,代码量少,适合个人项目或原型开发。
- 如果你需要团队协作、多语言支持、产品化交付,选TouchGFX。它的资源管理机制虽然学习曲线陡一点,但长期维护成本低。