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, "自定义字体示例");
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);
}
这个例子虽然简单,但涵盖了创建、换行、颜色、字体和动态更新。你可以在自己的开发板上跑一下,看看效果。
lv_label_set_text_fmt()、换行要设宽度、字体颜色按需定制。做到这三点,你的界面文字部分基本就稳了。
下一章我们会讲按钮控件,到时候会结合标签一起做个交互示例。敬请期待。