LVGL学习笔记-----标签控件(lv_label)
LVGL学习笔记-----标签控件(lv_label)
@@author: 明月清了个风
@@date: 2025.6.13
⭐️关于LVGL标签控件的一些笔记,对应课程3-1-1 ~ 3-1-5的内容
标签:用于显示文本的控件
盒子模型中的组成:
- LV_PART_MAIN矩形部分(盒子区域),填充值可用于在文本和背景之间添加空间
- LV_PART_SCROLLBAR当要展示的文本大于部件的大小时,显示的滚动条部分。
- LV_PART_SELECTED选中文本时,突出显示的部分,label只能只用text_color和bg_color样式属性
标签控件的创建
lv_obj_t * label = lv_label_create(parent);
标签内容的显示
-
直接显示字符串
lv_label_set_text(label, "123131323132");
-
也可以像
printf
那样格式化输出static int counter = 0; lv_label_set_text_fmt(label, "Counter: %d", counter++);
-
传参输出应使用指针变量
char * label_str = "111111" lv_label_set_text(label, label_str);
需要注意的第一点是,这里只能是
char *
而不能是char[]
变量,在函数内部定义的char []
为局部变量存储在栈中,当函数退出后内存失效,访问不安全,若要使用char []
,只能声明为static
或者全局变量,确保其作用域为全局。第二点需要注意的是,这里定义的字符串常量存储在只读数据段
.rodata
中,当使用char[]
进行定义时,实际上进行了一次字符串的复制操作,因此相对而言char *
会更节省时间和内存。当定义了两个不同的
char *
只想同一个字符串常量时,如下:char *a = "123"; char *b = "123";
对应的字符串常量在内存中只有一份(在
.rodata
段中只读),而使用不同的char[]
定义时,如下:char a[] = "123"; char b[] = "123";
实际上是复制了两份
这里还有一个知识点,
char[]
复制的这个字符串存在哪里,如果他是显示定义的全局变量,那么就存在数据段.data
中;如果是函数内部的局部变量,就存在栈上。重点是,字符串字面量123
永远都在.rodata
段中,前面说的存储位置都是复制的副本位置。
字体大小设置
lv_obj_set_style_text_font();
lv_style_set_text_font();
长模式
默认情况下,当文本的长度过长,标签的大小会被扩展成与文本一样的大小(LV_TEXT_CONTENT),当然也可以自己设置尺寸
lv_obj_set_size();
lv_obj_set_width();
lv_obj_set_height();
但是这样就会出现文本的尺寸大于标签的情况,需要进行一些处理,一般使用lv_label_set_long_mode(LV_LABEL_LONG_...)
设置
对应的宏有下面几种:
-
LV_LABEL_LONG_WRAP
如果有多个换行,且高度为LV_SIZE_CONTENT
或者足够高,那么高度会根据文本换行自动扩展,否则文本将被剪掉。下面是代码和对应的显示情况
char * label_str = "100askkkkkk11111111222222222"; lv_obj_t * label = lv_label_create(lv_screen_active()); lv_obj_set_size(label, 50, 50); lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP); lv_label_set_text(label, label_str);
-
LV_LABLE_LONG_DOT
如果文本过长,就保持大小并在末尾写3个点。下面是代码和对应的显示情况
char * label_str = "100askkkkkk11111111222222222"; lv_obj_t * label = lv_label_create(lv_screen_active()); lv_obj_set_size(label, 50, 50); lv_label_set_long_mode(label, LV_LABEL_LONG_DOT); lv_label_set_text(label, label_str);
需要注意的是,在所有模式中,只有这个会修改文本的内容,因此要保证存储这段text文本的地方要是可读可写的。
在上面的代码中,使用
char *
保存文本,指针保留了文本存储的地址,其实是无法修改文本的内容的,这段内容实际存储在代码段中(只读),但是在函数lv_label_set_text()
中有复制这段text的操作,因此这类的LV_LABEL_LONG_DOT
才合法,如果使用函数lv_label_set_text_static()
就会崩溃。 -
LV_LABEL_LONG_SCROLL
如果文本比标签宽,则可以水平来回滚动显示它。如果它很高(多个\n
换行)也可以垂直滚动。只滚动一个方向,且水平方向优先级更高。这是一个动态的效果,就不放实例了。
-
LV_LABEL_LONG_SCROLL_CIRCULAR
与上面这个相比就是只滚动一遍。 -
LV_LABEL_LONG_CILP
就是直接裁掉超出标签范围的文本。
文本的选择
也就是高亮被选择的文本,两个API
lv_label_get_text_selection_start(label, start_char_index);
lv_label_get_text_selection_end(label, end_char_index);
事件处理
lv_label
默认不接受输入事件,如果想要他响应如点击之类的操作,需要打开LV_OBJ_FLAG_CLICKABLE
,示例:
lv_obj_add_flag(label, LV_OBJ_FLAG_CLICKABLE);
课后思考
-
如何改变
label
文本的颜色?使用对应的函数即可
lv_obj_set_style_text_color(label, color, 0)
,这里的color
可以通过RGB进行创建lv_color_t c = lv_color_makr(red, green, blue);
也可以通过十六进制表示
lv_color_t c = lv_color_hex(0x123456);
那么要改变被选中的字的颜色,就要配合上面的文本的选择进行。
但是注意,根据官方文档:
LV_PART_SELECTED
告诉select text的样式,只能使用text_color
和bg_color
样式属性其他属性的更改不会发生变化。
-
如何刷新(实时、定时)label中的内容?(传感器数据)
使用定时器,创建定时器时传入用户数据为
label
指针,在定时器的回调函数中获取对应的label
,并设置数据。 -
char *
为函数中定义的指针变量,存储在栈上,当函数退出后栈空间释放,为什么还能使用lv_label_set_text_static
显示内容?因为
char*
指向的地址空间中为只读的字符串变量,而在lv_label_set_text_static
以及lv_label_set_text
中都将char *
指向的地址变量,也就是对应字符串在.rodata
段中的地址保存了下来,当栈上的char *
被释放后,该地址仍然有效,因此可以继续访问,这里又引出了char []
与其的对比,由于char[]
对字符串进行了复制,因此在lv_label_set_text_static
以及lv_label_set_text
中保存的实际上是新的复制的地址,并不是.rodata
段中的那个,因此在函数退出后再次访问label
中存下来的这个地址是不安全的。