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默认有固定宽高,如果不设置自适应,文字可能会被截断。我在项目中遇到过好几次,调试了半天发现文字只显示了一半,就是这个原因。

小技巧: LVGL的Label支持多种长模式(long_mode),比如自动换行、滚动显示等。如果文字太长,可以用lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL)让它滚动起来。

3.2 TouchGFX:用TextArea显示文本

TouchGFX的做法完全不同。它不让你在C代码里直接写字符串,而是通过一个叫“文本ID”的机制来管理所有文本。

流程是这样的:

  1. 在TouchGFX Designer里拖一个TextArea控件到屏幕
  2. 在文本资源(Texts)里定义一个文本ID,比如T_SINGLEUSEID1
  3. 在代码里通过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在资源文件里定义,实际字符串在运行时填充。这种做法在需要多语言支持的项目里特别有用——你只需要切换文本资源文件,不用改一行代码。

注意: TouchGFX的TextArea默认不支持自动换行。如果你需要多行文本,必须使用TextAreaWithWildcard,并手动设置换行符。我曾经在这个坑里爬了半天,后来才发现是控件类型选错了。

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 vs TouchGFX 代码结构对比 LVGL 结构 lv_label_create(lv_scr_act()) lv_label_set_text(label, "Hello World") lv_obj_align(label, CENTER, 0, 0) 全部在C代码中完成 优点:灵活、直接、调试方便 TouchGFX 结构 Designer中拖拽TextArea 定义文本ID (T_SINGLEUSEID1) 代码中引用TypedText 代码 + 资源文件分离 优点:规范、易维护、支持多语言

从这张图可以看得很清楚: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,最后内存耗尽系统崩溃。
重要提醒: 无论你用哪个框架,第一个Hello World项目一定要确保硬件环境(屏幕驱动、触摸校准)已经调通。否则你花半天时间写代码,结果屏幕一片黑,那种挫败感...嗯,我经历过。

3.6 小结:选择哪个框架?

回到最初的问题:LVGL和TouchGFX,第一个Hello World项目选哪个?

我的建议是:

  • 如果你追求快速上手、灵活调试,选LVGL。它的API直观,代码量少,适合个人项目或原型开发。
  • 如果你需要团队协作、多语言支持、产品化交付,选TouchGFX。它的资源管理机制虽然学习曲线陡一点,但长期维护成本低。