4. 基础控件-标签(lv_label):标签的创建、文本设置与动态更新、长文本自动换行、自定义字体与颜色

标签,说白了就是屏幕上显示文字的那个东西。你想想看,一个嵌入式界面,哪个界面能少了文字?不管是显示个温度值、设备状态,还是做个菜单选项,都离不开 lv_label。我个人习惯,每次新建项目,第一个测试的控件就是标签——因为它最简单,能最快验证我的显示驱动有没有问题。

4.1 标签的创建与基本设置

创建标签其实就两行代码的事。但别小看这两行,我在项目中遇到过有人把父对象传错了,结果文字死活显示不出来——嗯,这种坑踩过一次就记住了。

lv_obj_t * label = lv_label_create(lv_scr_act());  // 在当前屏幕创建标签
lv_label_set_text(label, "Hello, LVGL!");           // 设置文本内容

创建完标签,你还可以调整它的位置和大小。不过要注意,标签的宽高默认是自适应文本内容的,除非你手动设置 lv_obj_set_width()lv_obj_set_height()

小技巧: 如果你想让标签居中显示,可以用 lv_obj_align(label, LV_ALIGN_CENTER, 0, 0)。这个对齐函数我几乎每个项目都会用到,省去了手动计算坐标的麻烦。

4.2 文本设置与动态更新

静态文本谁都会写,但实际项目中,标签里的内容往往是动态变化的。比如显示一个计时器、网络信号强度,或者传感器读数。

动态更新文本,最常用的方法是 lv_label_set_text()。但这里有个性能问题——每次调用这个函数,LVGL 内部都会重新分配内存来存储新字符串。如果你频繁更新(比如每秒几十次),内存碎片会越来越严重。

我建议用 lv_label_set_text_fmt() 来处理格式化字符串,比如显示温度值:

float temperature = 25.6;
lv_label_set_text_fmt(label, "当前温度: %.1f°C", temperature);

这样写,代码简洁,而且可读性高。我曾经在一个数据采集项目里,每秒更新 10 次标签内容,用了半年都没出过内存问题。

注意: 如果你用 lv_label_set_text() 传入一个局部变量的指针,LVGL 内部会复制一份字符串。所以不用担心局部变量销毁后指针失效的问题。但反过来,如果你用 lv_label_set_text_static(),LVGL 不会复制字符串,只保存指针——这时候你必须保证那个字符串一直有效。

4.3 长文本自动换行

有时候你要显示一段很长的文字,比如设备说明、错误日志。如果不做换行处理,文字会超出屏幕边界,或者只显示一部分。

LVGL 提供了两种换行模式:

模式 宏定义 说明
不换行 LV_LABEL_LONG_DOT 超出部分用省略号代替
自动换行 LV_LABEL_LONG_WRAP 根据宽度自动换行
滚动显示 LV_LABEL_LONG_SCROLL 文字太长时滚动显示
裁剪 LV_LABEL_LONG_CLIP 超出部分直接裁剪掉

我个人最常用的是 LV_LABEL_LONG_WRAP。设置方法很简单:

lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
lv_obj_set_width(label, 200);  // 设置一个固定宽度,触发换行

为什么会这样?因为 LVGL 的换行逻辑是基于标签的宽度来计算的。你不设置宽度,它默认自适应文本长度,那就永远不会换行。我记得第一次用这个功能时,折腾了半天才发现是宽度没设——嗯,这种低级错误谁都会犯。

核心要点: 自动换行必须同时做两件事——设置换行模式 + 设置固定宽度。缺一不可。

4.4 自定义字体与颜色

默认字体虽然能用,但说实话,有点丑。做产品嘛,字体和颜色是提升质感的关键。

4.4.1 自定义字体

LVGL 支持使用外部字体文件,比如 .ttf.woff。你需要用 LVGL 的字体转换工具(比如 lv_font_conv)把字体文件转成 C 语言数组,然后编译进项目。

转换时,你可以指定需要的字符范围。比如只用到 ASCII 字符,那就只转这部分,能省不少内存。我做过一个智能家居项目,只需要显示数字和几个汉字,转出来的字体文件才 2KB 不到。

使用自定义字体:

lv_obj_set_style_text_font(label, &my_custom_font, 0);
lv_label_set_text(label, "自定义字体示例");
提示: 如果你要显示中文,记得在转换字体时包含中文字符范围(U+4E00 ~ U+9FFF)。否则中文会显示成方框。这个坑我帮好几个同事排查过。

4.4.2 文本颜色

颜色设置也很直观。LVGL 用 lv_color_t 类型表示颜色,你可以用 lv_color_hex()lv_color_make() 来创建颜色值。

lv_obj_set_style_text_color(label, lv_color_hex(0xFF0000), 0);  // 红色
lv_obj_set_style_text_opa(label, 128, 0);                       // 半透明

这里有个细节——第二个参数 0 表示局部样式。如果你想让所有标签都使用同一种颜色,可以设置全局样式。但我建议初学者先用局部样式,逻辑更清晰。

我曾经在一个车载仪表盘项目里,用不同颜色区分警告等级:绿色表示正常,黄色表示注意,红色表示危险。配合动态更新,效果非常直观。

4.5 综合示例

最后,给你一个完整的示例,把今天讲的内容串起来:

// 创建标签
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_obj_set_width(label, 240);                    // 设置宽度,用于换行
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP); // 自动换行
lv_obj_align(label, LV_ALIGN_TOP_LEFT, 10, 10);  // 左上角对齐

// 设置自定义字体和颜色
lv_obj_set_style_text_font(label, &my_font_16, 0);
lv_obj_set_style_text_color(label, lv_color_hex(0x333333), 0);

// 动态更新文本
int count = 0;
while(1) {
    lv_label_set_text_fmt(label, "运行次数: %d\n这是一段会自动换行的长文本,用来演示标签的各种功能。", count++);
    lv_task_handler();
    lv_delay_ms(1000);
}

这个例子虽然简单,但涵盖了创建、换行、颜色、字体和动态更新。你可以在自己的开发板上跑一下,看看效果。

总结一下: 标签是 LVGL 最基础的控件,但用好它并不简单。记住三点——动态更新用 lv_label_set_text_fmt()、换行要设宽度、字体颜色按需定制。做到这三点,你的界面文字部分基本就稳了。

下一章我们会讲按钮控件,到时候会结合标签一起做个交互示例。敬请期待。