LVGL 快速入门:对象、事件与样式介绍
LVGL(Light and Versatile Graphics Library)是一款开源、轻量级且功能丰富的嵌入式 GUI 库,广泛应用于 STM32、ESP32 等 MCU/MPU 的图形界面开发。它提供了对象系统、样式系统、事件机制、布局管理、动画以及文件系统等完整功能,使开发者能够在资源有限的硬件上快速构建美观、流畅的界面。
LVGL
LVGL
一、概念
LVGL(Light and Versatile Graphics Library) 是一个开源的嵌入式 GUI(图形用户界面)库,专门用于 小型 MCU/MPU 的显示屏开发,比如 STM32、ESP32、NXP i.MX 等。它特点是轻量、移植灵活、功能丰富。
LVGL 所有的对象都在lv_obj_t结构体进行变化。
lv_obj_t结构体:
typedef struct _lv_obj_t {
const lv_obj_class_t * class_p;
struct _lv_obj_t * parent;
_lv_obj_spec_attr_t * spec_attr;
_lv_obj_style_t * styles;
#if LV_USE_USER_DATA
void * user_data;
#endif
lv_area_t coords;
lv_obj_flag_t flags;
lv_state_t state;
uint16_t layout_inv : 1;
uint16_t readjust_scroll_after_layout : 1;
uint16_t scr_layout_inv : 1;
uint16_t skip_trans : 1;
uint16_t style_cnt : 6;
uint16_t h_layout : 1;
uint16_t w_layout : 1;
uint16_t being_deleted : 1;
} lv_obj_t;
二、对象
在 LVGL 中,一切界面元素都是对象(lv_obj_t),对象是 GUI 系统的核心概念。理解对象的结构和特性,才能真正掌握 LVGL 的使用方法。
创建对象时候,首先要创建一个父类,这个父类有两种
- 直接使用活动屏幕创建,对象的父类是活动屏幕
- 使用对象A创建,创建后,新的对象B是对象A的子类
2.1 父对象与子对象的关系
- 子对象默认是在父对象的左上角创建
- 子对象会随着父对象移动
- 子对象位置超出父对象范围,超出部分不显示
2.2 基础对象
创建基础对象
lv_obj_t* obj1 = lv_obj_create(lv_src_act());
- lv_scr_act() 获取活动屏幕
- lv_obj_set_size(对象, w, h) 设置对象大小
- lv_obj_set_pos(对象, x, y) 设置位置
三、 部件
3.1 部件的创建
lv_部件名_create();
例如:创建一个开关
lv_swtich_create();
3.2 lv_obj部件
lv_obj
是 基础对象,相当于 LVGL 的“容器”。- 其他所有控件(如按钮
lv_btn
、标签lv_label
、开关lv_switch
等)都是基于lv_obj
扩展的。 - 你可以单独使用
lv_obj
来创建一个矩形区域,用于显示颜色、作为容器或作为布局的父对象。
3.3 lv_label 标签部件
标签组成部分:
- 主体 LV_PART_MAIN
- 滚动条 LV_PART_SCROLLBAR
- 选中的文本 LV_PART_SELECTED
3.3.1 创建标签部件
lv_obj_t* label = lv_label_create(parent);
3.3.1.1 设置标签文本
存储文本的内存动态分配
lv_label_set_text(部件名,"文本内容");
存储文本在指定的缓冲区中
lv_label_set_text_static(部件名,"文本内容");
由于存储的区域是代码段,只读。后面如果发生更改就会报错。
格式化显示文本
lv_label_set_text_fmt(部件名, "内容 %d",10); // 后面内容部分就类似printf一样,有占位符
3.3.2 设置标签样式
3.3.2.1 背景颜色
lv_obj_set_style_bg_color(部件名, 颜色, 选择器);
标签的背景颜色透明度默认是透明的,所以单独设置背景颜色看起来是没有生效的。
lv_obj_set_style_bg_opa(部件名, 透明度 ,选择器); // 透明度范围是 0~255
通过这个修改透明度就可以显示背景颜色了。
3.3.2.2 字体大小
lv_obj_set_style_text_font(部件名, 字体, 选择器);
lv.conf.h 里面有字体的宏,使用前需要将宏置1。
3.3.2.3 文本颜色
lv_obj_set_style_text_color(部件名, 颜色, 选择器);
3.3.2.4 设置个别文本的字体颜色
lv_label_set_recolor(部件名, true); // 开启重新着色功能
lv_label_set_text(部件名, "文本信息1 #ff0000 文本信息2 # ");
3.3.5 文本阴影
多复制一份文本,颜色调淡,偏移一定位置。
3.4 长文本模式(长模式)
- 默认情况下,如果没有限定标签部件大小,标签大小自动为文本大小。
- 长文本模式是可以手动修改文本显示模式
lv_label_set_long_mode(label, LV_LABEL_LONG_...);
在按钮里显示标签信息
#ff0000 文本 # 可以自定义颜色
3.4 lv_but 按钮部件
3.4.1 创建按钮部件
lv_obj_t* btn = lv_btn_create(parent);
3.4.2 设置样式
lv_obj_set_size( btn, 100, 50 );
lv_obj_set_align( btn, LV_ALIGN_CENTER );
lv_obj_set_style_bg_color( btn,lv_color_hex(Oxffe1d4), LV_STATE_PRESSED );
3.4.3 添加事件
按钮状态切换
lv_obj_add_flag( btn, LV_OBJ_FLAG_CHECKABLE );
监测事件值发生的变化
lv_obj_add_event_cb( btn, event_cb,LV_EVENT_VALUE_CHANGED,NULL );
3.5 lv_switch 按钮部件
组成部分:
- 主体 LV_PART_MAIN
- 手柄 LV_PART_KNOB
- 指示器 LV_PART_INDICATOR
3.5.1 创建开关部件
lv_obj_t* switch1 = lv_swtich_create(parent);
3.5.2 设置样式
设置手柄颜色
lv_obj_set_style_bg_color( switch1,lv_color_hex(Oxffe1d4), LV_PART_KNOB);
设置指示器颜色
lv_obj_set_style_bg_color( switch1,lv_color_hex(Oxffe1d4), LV_PART_INDICARTOR);
直接设置发现貌似没有被更改。其实是已经更改了,不过开关默认是关闭的导致颜色被覆盖。
3.5.3 添加、清除开关状态
添加状态
lv_obj_add_state(swtich1, 需要添加的状态);
删除状态
lv_obj_clear_state(swtich1, 需要删除的状态);
状态可以 ‘‘与’’ 上 LV_STATE_DISABLE 变成状态不可修改。
3.5.4 判断开关状态
是否处于某个值,返回bool类型,开为1,关为0
lv_obj_has_state(部件名,状态);
3.6 lv_chechbox 复选框部件
组成部分:
- 主体 LV_PART_MAIN
- 勾选框 LV_PART_INDICATOR
3.6.1 创建复选框部件
lv_obj_t* checkbox = lv_checkbox_create(parent);
3.6.2 文本设置
设置文本内容
lv_checkbox_set_text(部件名, "文本");
设置文本和勾选框的间距
lv_obj_set_style_pad_column(部件名, 间距, 选择器);
3.7 lv_img 图片部件
3.7.1 lv_img 图片部件使用
组成部分:
- 主体 LV_PART_MAIN
3.7.1.1 创建图片部件
lv_obj_t* img = lv_img_create(parent);
3.7.1.2 设置图片源
图片源有两种方式:
- 将图片变成.c文件,用.c文件显示图片。
- 图片使用二进制文件展示
官方有转换工具 https://lvgl.io/tools/imageconverter,需要注意LVGL的版本对应!
LV_IMG_DECLARE(img_bird); // 声明图片
lv_img_set_src(img. &img_bird); // 设置图片源
3.7.1.3 设置图片偏移
图片偏移多余的部分会跑回开头。例如下面这段文字是你的图片信息 “我是图片123”,设置x轴偏移2,就会变成 “23我是图片1”,"23"就到前面去了。Y轴同理
lv_img_set_offset_x(img, 偏移量); // x轴偏移
lv_img_set_offset_y(img, 偏移量); // y轴偏移
3.7.1.4 图片重新着色
有种加滤镜的效果
lv_obj_set_style_img_recolor(img, lv_color_hex(Oxffe1d2), LV_PART_MAIN);
lv_obj_set_style_img_recolor_opa(img, 150, LV_PART_MAIN);
记住设置透明度,不然无法正常显示着色
3.7.1.5 设置图片缩放、旋转
lv_img_set_zoom(img, 512);
lv_img_set_angle(img, 900);
3.7.1.6 设置中心点
默认中心点在图片的正中间,图片缩放旋转都是根据这个中心点进行的。
lv_obj_update_layout(img); // 更新图片布局信息
lv_img_set_pivot(img, 0, 0); // 设置中心点
3.7.2 图片的设置
3.7.2.1 显示图片需要开启LVGL对标准IO的支持
lv_conf.h
文件中:
-
LV_USE_FS_STDIO
- 是否启用C标准库文件系统驱动
- 1启用
- 0不启用
-
LV_FS_STDIO_LETTER 配置盘符
'F'
→ FatFS (SD 卡)'S'
→ StdIO (标准文件系统)'U'
→ UserFS (用户自定义)
-
LV_FS_STDIO_PATH
-
设置文件操作的“根路径”。
-
LVGL 在拼接文件路径时,会自动把用户路径加到这个前缀后面。
-
举例:
#define LV_FS_STDIO_PATH "D:/lvgl_assets"
如果你在 LVGL 里写:
lv_img_set_src(img, "A:/images/pic.png");
实际 fopen 的路径会变成:
D:/lvgl_assets/images/pic.png
-
-
LV_FS_STDIO_CACHE_SIZE
- 为
lv_fs_read()
设置缓存大小(字节数)。 0
→ 不启用缓存,每次读直接调用fread()
。>0
→ 分配一块缓存,用于提升连续小块读取的性能。
- 为
可以按照这个快速设置
3.7.2.2 开启图片格式接口
将需要的图片接口宏置1
3.7.2.3 调大malloc的空间
这里按需设置LV_MEM_SIZE大小,主要是防止图片过大内存会溢出。
3.8 lv_gif 动图部件
3.8.1 创建动图部件
lv_obj_t * gif1 = lv_gif_create(parent);
3.8.2 设置样式
设置gif路径
lv_gif_set_src(部件名, "gif图路径");
重新播放gif动画
lv_gif_restart(部件名);
四、部件的基本属性
4.1 大小 size
设置宽度
lv_obj_set_width(obj, new_width);
设置高度
lv_obj_set_height(obj, new_height);
同时设置宽度、高度
lv_obj_set_size(obj, new_width, new_height);
4.2 位置 position
- 设置部件位置时,坐标原点在父对象的左上角
设置X轴坐标
lv_obj_set_x(obj, new_x, new_y);
设置Y轴坐标
lv_obj_set_y(obj, new_y);
同时设置X、Y轴坐标
lv_obj_set_pos(obj, new_x, new_y);
4.3 对齐alignment
参照父对象对齐
lv_obj_set_align(obj, LV_ALIGN_...);
参照父对象对齐,在进行偏移
lv_obj_align(obj, LV_ALIGN_.., x, y);
参照其他对象对齐(无父子关系),再进行偏移
lv_obj_align_to(obj_to_align, obj_referece, LV_ALIGN_..., x, y);
- obj_to_align 需要对齐的对象
- obj_referece 基准对象
4.3.1 对齐模式
分为内部与外部。内部与外部是基于类来规定的。
4.4 样式 styles
4.4.1 添加样式
- 添加普通样式:
static lv_style_t style;
lv_style_init(&style);
lv_style_set_bg_color(&style, lv_color_hex(0xf4b183));
样式使用:
lv_obj_t* obj = lv_obj_create(lv_scr_act());
lv_obj_add_style(obj, &style, LV_STATE_DEFAULT);
- 添加本地样式:
lv_obj_t* obj = lv_obj_create(lv_scr_act());
lv_obj_set_style_bg_color(obj, lv_color_hex(0xf4b183), LV_STATE_DEFAULT);
4.4.2 样式的部位
4.4.3 样式的属性
- 轮廓在边框的外面
- opa 透明度 越小越透明
4.4.4 设置部件中某个部分的样式
lv_obj_t* obj = lv_obj_create(lv_scr_act());
lv_obj_set_style_bg_color(obj, lv_color_hex(0xf4b183),
LV_STATE_DEFAULT | LV_PART_INDICATOR);
4.5 盒子模型
盒子是有默认的样式的,要想取消默认样式可以通过相关函数设置。
五、events 事件
监听某个部件发生某种情况执行某种结果。
5.1 事件的创建
lv_obj_add_event_cb(obj 部件名, event_cb 回调事件, filter 事件, user_date 参数);
static void my_event(lv_event_t *e)
{
printf("LV_EVENT_CLICKED\n");
}
void mylv_event_cb()
{
lv_obj_t *obj1 = lv_obj_create(lv_scr_act());
lv_obj_add_event_cb(obj1, my_event, LV_EVENT_CLICKED, NULL);
}
回调函数的结构体 lv_event_t *e
typedef struct _lv_event_t {
struct _lv_obj_t * target;
struct _lv_obj_t * current_target;
lv_event_code_t code;
void * user_data;
void * param;
struct _lv_event_t * prev;
uint8_t deleted : 1;
uint8_t stop_processing : 1;
uint8_t stop_bubbling : 1;
} lv_event_t;
5.2 事件动作
按下/释放相关
动作 | 事件类型 | 描述 |
---|---|---|
按下 | LV_EVENT_PRESSED |
手指/鼠标按下对象时触发 |
松开 | LV_EVENT_RELEASED |
手指/鼠标释放对象时触发 |
点击 | LV_EVENT_CLICKED |
按下再松开且位置在对象范围内触发 |
双击 | LV_EVENT_SHORT_CLICKED / LV_EVENT_LONG_PRESSED_REPEAT |
短按重复触发或长按 |
移动/滑动相关
动作 | 事件类型 | 描述 |
---|---|---|
拖动开始 | LV_EVENT_DRAG_BEGIN |
开始拖动对象时触发 |
拖动中 | LV_EVENT_PRESSING |
按住对象并移动时持续触发 |
拖动结束 | LV_EVENT_DRAG_END |
松开对象或拖动结束时触发 |
惯性拖动开始 | LV_EVENT_DRAG_THROW_BEGIN |
拖动惯性开始时触发 |
动作 | 事件类型 | 描述 |
---|---|---|
获得焦点 | LV_EVENT_FOCUSED |
对象被选中/高亮时触发 |
失去焦点 | LV_EVENT_DEFOCUSED |
对象失去焦点时触发 |
值改变 | LV_EVENT_VALUE_CHANGED |
用于开关、滑块、复选框等值改变时触发 |
状态/焦点相关
动作 | 事件类型 | 描述 |
---|---|---|
长按 | LV_EVENT_LONG_PRESSED |
按下超过一定时间触发 |
长按重复 | LV_EVENT_LONG_PRESSED_REPEAT |
长按期间每隔一定时间重复触发 |
5.3 关于回调函数获取部件信息有关函数
5.3.1 lv_event_get_code(e)
-
获取当前事件的类型,例如
LV_EVENT_CLICKED
、LV_EVENT_VALUE_CHANGED
。 -
典型用法:
if (lv_event_get_code(e) == LV_EVENT_CLICKED) { printf("Object clicked!\n"); }
5.3.2 lv_event_get_target(e)
-
获取触发事件的目标对象
lv_obj_t*
。 -
相当于告诉你是谁触发了这个事件。
-
典型用法:
lv_obj_t *obj = lv_event_get_target(e); lv_obj_set_style_bg_color(obj, lv_color_hex(0xFF0000), 0); // 点击变红
5.3.3 lv_event_get_current_target(e)
- 获取当前执行回调的对象(可能和
target
不同,用在冒泡/捕获事件时)。
5.3.4 lv_event_get_user_data(e)
- 获取你在
lv_obj_add_event_cb
注册时传进去的user_data
。 - 可以用来传递额外参数,比如结构体指针。
5.3.5 其他函数:
- lv_event_get_indev(e):获取触发事件的输入设备(如触摸屏)。
lv_event_stop_bubbling(e)
:阻止事件冒泡。lv_event_stop_processing(e)
:阻止后续回调执行。
六、颜色
6.1 RGB 三原色
从红色、绿色和蓝色通道值创建颜色
//All channels are 0-255
lv_color_t c = lv_color_make(red, green, blue);
//From hex code 0x000000..0xFFFFFF interpreted as RED + GREEN + BLUE
lv_color_t c = lv_color_hex(0x123456);
//From 3 digits. Same as lv_color_hex(0x112233)
lv_color_t c = lv_color_hex3(0x123);
6.2 HSV 色调饱和值
根据色相、饱和度和值创建颜色
//h = 0..359, s = 0..100, v = 0..100
lv_color_t c = lv_color_hsv_to_rgb(h, s, v);
//All channels are 0-255
lv_color_hsv_t c_hsv = lv_color_rgb_to_hsv(r, g, b);
//From lv_color_t variable
lv_color_hsv_t c_hsv = lv_color_to_hsv(color);
6.3 调色板(内置颜色)
lvgl是有提供很多内置颜色(palette)的,如下:
LV_PALETTE_RED
LV_PALETTE_PINK
LV_PALETTE_PURPLE
LV_PALETTE_DEEP_PURPLE
LV_PALETTE_INDIGO
LV_PALETTE_BLUE
LV_PALETTE_LIGHT_BLUE
LV_PALETTE_CYAN
LV_PALETTE_TEAL
LV_PALETTE_GREEN
LV_PALETTE_LIGHT_GREEN
LV_PALETTE_LIME
LV_PALETTE_YELLOW
LV_PALETTE_AMBER
LV_PALETTE_ORANGE
LV_PALETTE_DEEP_ORANGE
LV_PALETTE_BROWN
LV_PALETTE_BLUE_GREY
LV_PALETTE_GREY
可以使用下面函数使用它们:
lv_palette_main(palette)
-
获取调色板的 主色 (main color)。
-
例如:
lv_color_t c = lv_palette_main(LV_PALETTE_RED); lv_obj_set_style_bg_color(obj, c, 0);
lv_palette_lighten(palette, lvl)
-
获取调色板的 更亮的颜色。
-
lvl
范围通常是1~3
(越大越亮)。 -
例如:
lv_color_t c = lv_palette_lighten(LV_PALETTE_BLUE, 2); lv_obj_set_style_bg_color(obj, c, 0);
lv_palette_darken(palette, lvl)
-
获取调色板的 更暗的颜色。
-
lvl
范围通常是1~4
(越大越暗)。 -
例如:
lv_color_t c = lv_palette_darken(LV_PALETTE_GREEN, 3); lv_obj_set_style_bg_color(obj, c, 0);
使用场景 | 推荐格式 |
---|---|
小图标 / 图形控件,有限色 | CF_INDEXED_1/2/4/8_BIT |
透明图标 / UI 界面元素 | CF_TRUE_COLOR_ALPHA 或 CF_RGB565A8 |
背景图 / 全彩照片 | CF_TRUE_COLOR 或 CF_TRUE_COLOR_CHROMA |
纯色遮罩 / 字体 | CF_ALPHA_1/2/4/8_BIT |
通过这个链接查看调色板的具体颜色 VUETIFY:https://vuetifyjs.com/en/styles/colors/#material-colors
七、中文字库
- 选择字体文件(ttf, otf 等格式)
- 将字体文件转换成LVGL需要的字体库。(官方字体库在线转换工具链接: https://lvgl.io/tools/fontconverter)
- 选择字体转换的范围,范围越大字体涵盖就越多,相应的占用内存更多。(官方字体范围链接: https://lvgl.100ask.net/8.2/tools/fonts-zh-source.html)
注意:字体名称在创建的时候请注意C语言的命名规范,避免出现
-
(短横杠) 这类的。
- 声明字体
LV_FONT_DECLARE(字体名)
- 调用字体
lv_obj_t* font_label = lv_label_create(lv_scr_act()); // 创建label标签
lv_obj_set_style_text_font(font_label, &声明的字体名, LV_STATE_DEFAULT); // 为label调用字体
lv_label_set_text(font_label, "文本内容"); // 设置文本内容
7.2 可能遇到的bug
7.2.1 static_bitmap = 0 不认识
把这段话注释就好,我的是v8.2版本的。
7.2.2 中文字库过大,需要开启大字库支持
在文件 lv_conf.h
中
#define LV_FONT_FMT_TXT_LARGE 1 // 置1
对于出现旧的错误,建议清除已有的缓解(make clean 清除之前编译的文件)重新编译。
十、定时器
10.1 定时器是什么
在 LVGL 里,定时器(lv_timer_t
)就是一个 周期性执行的任务。它和你在 RTOS 或裸机里写的硬件定时器不一样,它依赖于 lv_timer_handler()
的运行,所以要保证主循环里定时调用 lv_timer_handler()
。
10.2 创建定时器
lv_timer_t * lv_timer_create(lv_timer_cb_t timer_xcb,
uint32_t period,
void * user_data);
timer_xcb
:回调函数period
:间隔时间,单位毫秒user_data
:用户数据(传参)
示例
static void my_timer_cb(lv_timer_t * timer)
{
int * count = timer->user_data;
(*count)++;
printf("tick %d\n", *count);
}
void init_timer(void)
{
static int cnt = 0;
lv_timer_t * timer = lv_timer_create(my_timer_cb, 1000, &cnt);
}
10.3 常用操作
- 删除定时器
lv_timer_del(timer);
- 重置定时器(下次执行重新开始计时)
lv_timer_reset(timer);
- 修改周期
lv_timer_set_period(timer, 500); // 改成 500ms
- 设置执行次数
lv_timer_set_repeat_count(timer, 10); // 执行10次后自动删除
- 暂停 / 恢复
lv_timer_pause(timer); // 暂停
lv_timer_resume(timer); // 恢复
以上就是我对LVGL学习笔记,笔记中还有很多LVGL的部件和知识点未提及,可以通过LVGL官方文档进行查阅,也可以通过百问网查询资料学习(百问网链接:https://lvgl.100ask.net/8.2/index.html)。
更多推荐
所有评论(0)