LVGL轻量级图形库入门指南:嵌入式GUI开发必备技能
《LVGL轻量级图形库入门指南》摘要: LVGL是一款开源嵌入式GUI库,以轻量化和强大功能著称。文章系统介绍了LVGL的核心概念:1)显示屏与屏幕对象的区别;2)Widget树构建方法;3)事件处理机制。重点讲解了Widget操作技巧,包括创建、修改和删除Widget,以及部件(Part)和状态(State)的应用。通过代码示例展示了样式设置和主题配置方法,并提供了"Hello Wor
LVGL轻量级图形库入门指南:嵌入式GUI开发必备技能
前言
大家好,今天给各位分享一个我在嵌入式GUI开发中的"神器"——LVGL图形库。作为嵌入式开发领域的"颜值担当",LVGL凭借其轻量级设计和强大功能,成为了众多开发者的首选。无论你是刚入门的小白,还是经验丰富的老手,这篇文章都能帮你快速上手LVGL,打造精美的嵌入式图形界面!
一、LVGL基础概念
1.1 什么是LVGL?
LVGL (Light and Versatile Graphics Library) 是一款免费开源的图形库,提供了创建嵌入式GUI所需的一切,具有易用的移动端风格图形元素、漂亮的视觉效果和低内存占用的特点。
1.2 LVGL数据流概览
LVGL的核心工作流程如下:
- 将LVGL添加到你的项目中
- 提供输入方式和显示驱动
- 连接时钟接口,让LVGL知道当前时间
- 定期调用定时器处理函数
- 构建一个或多个Widget树,以便LVGL渲染交互式UI
其中,定时器处理函数驱动LVGL的定时器执行以下周期性任务:
- 刷新显示屏
- 读取输入设备
- 基于用户输入(和其他因素)触发事件
- 运行动画
- 执行用户创建的定时器
1.3 应用程序的工作
初始化后,应用程序的主要工作是:
- 在需要时创建Widget树
- 管理这些Widget生成的事件(通过用户交互等)
- 在不再需要时删除它们
剩下的一切,都交给LVGL来处理!
二、重要概念详解
2.1 显示屏与屏幕的区别
初学LVGL,很多同学容易混淆以下两个概念:
- 显示屏(Display Panel):物理显示像素的硬件
- 显示对象(lv_display):RAM中代表LVGL将渲染到的显示屏的对象
- 屏幕对象:Widget树中的"根"Widget,每个屏幕都"附加"到特定显示对象
2.2 默认显示屏与活动屏幕
- 默认显示屏:创建的第一个显示(lv_display)对象
- 活动屏幕:当前显示的屏幕(及其子Widget)
2.3 小部件(Widgets)
初始化LVGL后,应用程序创建一个Widget树,LVGL将其渲染到关联的显示屏以创建用户界面。
Widget是LVGL的"智能"图形元素,包括:
- 基本Widget(简单矩形和屏幕)
- 按钮
- 标签
- 复选框
- 开关
- 滑块
- 图表等
2.3.1 创建Widget树
应用程序首先获取屏幕Widget的指针,然后将其他Widget添加为此屏幕的子Widget。Widget在创建时自动添加为其父Widget的子Widget。
任何Widget都可以包含其他Widget。例如,如果你希望按钮上有文字,可以创建一个标签Widget并将其添加为按钮的子Widget。
// 创建按钮
lv_obj_t * btn = lv_button_create(lv_screen_active());
// 创建标签并添加到按钮中
lv_obj_t * label = lv_label_create(btn);
lv_label_set_text(label, "按钮文字");
子Widget成为父Widget的"一部分",这种关系意味着:
- 当父Widget移动时,其子Widget也跟随移动
- 当父Widget被删除时,其子Widget也被删除
- 子Widget仅在其父Widget的边界内可见
三、Widget操作详解
3.1 创建Widget
Widget通过调用如下形式的函数创建:
lv_obj_t * widget = lv_<类型>_create(parent);
例如:
// 创建一个滑块并添加到当前活动屏幕
lv_obj_t * slider1 = lv_slider_create(lv_screen_active());
3.2 修改Widget
所有Widget通用的属性通过以下形式的函数设置:
lv_obj_set_<属性名>(widget, <值>);
例如:
// 设置滑块的位置和大小
lv_obj_set_x(slider1, 30); // 设置X坐标为30
lv_obj_set_y(slider1, 10); // 设置Y坐标为10
lv_obj_set_size(slider1, 200, 50); // 设置宽度为200,高度为50
特定类型的Widget还有自己的专有属性,通过以下形式的函数设置:
lv_<类型>_set_<属性名>(widget, <值>);
例如:
// 设置滑块的值(带动画效果)
lv_slider_set_value(slider1, 70, LV_ANIM_ON);
3.3 删除Widget
删除任何Widget及其子Widget:
lv_obj_delete(widget);
四、事件处理
事件用于通知应用程序Widget发生了什么。你可以为Widget分配一个或多个回调函数,当Widget被点击、释放、拖动、删除等时调用。
// 为按钮添加点击事件回调
lv_obj_add_event_cb(btn, my_btn_event_cb, LV_EVENT_CLICKED, NULL);
// 事件回调函数
void my_btn_event_cb(lv_event_t * e)
{
printf("按钮被点击了\n");
}
事件回调接收参数lv_event_t * e
,包含当前事件代码和其他事件相关信息:
// 获取事件代码
lv_event_code_t code = lv_event_get_code(e);
// 获取触发事件的Widget
lv_obj_t * widget = lv_event_get_target(e);
五、部件与状态
5.1 部件(Parts)
Widget由一个或多个部件构成。例如,按钮只有一个部件叫做LV_PART_MAIN
,而滑块有LV_PART_MAIN
、LV_PART_INDICATOR
和LV_PART_KNOB
三个部件。
通过使用部件,你可以为Widget的子元素应用不同的样式。
5.2 状态(States)
Widget可以处于以下状态的组合:
LV_STATE_DEFAULT
:正常,释放状态LV_STATE_CHECKED
:切换或选中状态LV_STATE_FOCUSED
:通过键盘、编码器或触摸板/鼠标点击获得焦点LV_STATE_FOCUS_KEY
:通过键盘或编码器获得焦点LV_STATE_EDITED
:被编码器编辑LV_STATE_HOVERED
:鼠标悬停LV_STATE_PRESSED
:被按下LV_STATE_SCROLLED
:正在滚动LV_STATE_DISABLED
:禁用状态
检查Widget是否处于给定状态:
if(lv_obj_has_state(widget, LV_STATE_PRESSED)) {
// Widget正在被按下
}
添加或移除状态:
// 添加状态
lv_obj_add_state(widget, LV_STATE_CHECKED);
// 移除状态
lv_obj_remove_state(widget, LV_STATE_PRESSED);
六、样式与主题
6.1 样式(Styles)
样式实例包含背景颜色、边框宽度、字体等描述Widget外观的属性。
// 创建并初始化样式
static lv_style_t style1;
lv_style_init(&style1);
// 设置样式属性
lv_style_set_bg_color(&style1, lv_color_hex(0xa03080)); // 设置背景色
lv_style_set_border_width(&style1, 2); // 设置边框宽度为2像素
还可以为Widget添加本地样式属性:
// 为滑块的指示器部分在按下状态下设置背景色
lv_obj_set_style_bg_color(slider1, lv_color_hex(0x2080bb), LV_PART_INDICATOR | LV_STATE_PRESSED);
6.2 主题(Themes)
主题是Widget的一组默认样式。创建Widget时,会自动应用来自活动主题的样式。
应用程序的主题是在lv_conf.h
中的编译时配置设置。
七、实战案例
7.1 Hello World标签
// 改变活动屏幕的背景颜色
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0x003a57), LV_PART_MAIN);
// 创建一个白色标签,设置其文本并居中对齐
lv_obj_t * label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "你好,世界");
lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0xffffff), LV_PART_MAIN);
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
7.2 带标签的按钮及点击事件
// 点击事件回调函数
static void btn_event_cb(lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * btn = lv_event_get_target_obj(e);
if(code == LV_EVENT_CLICKED) {
static uint8_t cnt = 0;
cnt++;
// 获取按钮的第一个子元素(标签)并更改其文本
lv_obj_t * label = lv_obj_get_child(btn, 0);
lv_label_set_text_fmt(label, "按钮点击: %d", cnt);
}
}
// 创建按钮
lv_obj_t * btn = lv_button_create(lv_screen_active()); // 在当前屏幕添加按钮
lv_obj_set_pos(btn, 10, 10); // 设置位置
lv_obj_set_size(btn, 120, 50); // 设置大小
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL); // 分配回调函数
// 为按钮添加标签
lv_obj_t * label = lv_label_create(btn);
lv_label_set_text(label, "按钮");
lv_obj_center(label);
7.3 创建滑块并在标签上显示其值
static lv_obj_t * label;
// 滑块事件回调函数
static void slider_event_cb(lv_event_t * e)
{
lv_obj_t * slider = lv_event_get_target_obj(e);
// 更新文本
lv_label_set_text_fmt(label, "%d", lv_slider_get_value(slider));
lv_obj_align_to(label, slider, LV_ALIGN_OUT_TOP_MID, 0, -15); // 对齐到滑块上方
}
// 在显示屏中央创建滑块
lv_obj_t * slider = lv_slider_create(lv_screen_active());
lv_obj_set_width(slider, 200); // 设置宽度
lv_obj_center(slider); // 对齐到父元素(屏幕)中央
lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL); // 分配事件函数
// 在滑块上方创建标签
label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "0");
lv_obj_align_to(label, slider, LV_ALIGN_OUT_TOP_MID, 0, -15); // 对齐到滑块上方
八、MicroPython支持
LVGL甚至可以与MicroPython一起使用:
# 初始化
import display_driver
import lvgl as lv
# 创建带标签的按钮
scr = lv.obj()
btn = lv.button(scr)
btn.align(lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text('你好,世界!')
lv.screen_load(scr)
最后
以上就是LVGL图形库的入门指南,希望对大家有所帮助!这个库虽然轻量级,但功能十分强大,尤其适合资源受限的嵌入式系统。我个人在多个项目中都使用了LVGL,体验非常棒,上手速度快,界面效果好,性能也相当不错。
如果你对文章内容有任何疑问,或者在使用LVGL过程中遇到什么困难,欢迎在评论区留言讨论。别忘了点赞、收藏、关注,我会持续分享更多嵌入式开发干货!
更多推荐
所有评论(0)