LVGL开发指导手册
一,简介
介绍
LVGL(轻度综合图形界面库)作为一个免费开源图形库能够提供几乎所有的嵌入式GUI。该开源库有使用方便,画面美观,内存占用低等优点。
1,收集资料 2,窗口初始化 3,控件 创建 布局 4,回调 5,切屏幕
二,资料路径
1,ESP32-S2-HMI-DevKit-1 使用说明:https://github.com/espressif/esp-dev-kits/tree/master/esp32-s2-hmi-devkit-1
2,LVGL官方文档:https://docs.lvgl.io/v7/en/html/get-started/quick-overview.html
中文地址:http://weidongshan.gitee.io/lvgl_100ask_doc/
英文地址:https://docs.lvgl.io/master/index.html
3,开发实例lv_examples:https://github.com/lvgl/lv_examples/tree/41a55a10e359683ae40c2273a311269ae4bbf9ee
三,开发步骤
1,在项目中添加LVGL
窗口初始化,以下步骤为LVGL在有触摸屏显示的嵌入式系统中的设置:
1,下载或使用命令行从
GITHUB
复制git clone https://github.com/lvgl/lvgl.git
2,将下载后的
lvgl
文件夹复制到项目文件夹3,将
lvgl/lv_conf_temp.h
库改名为lv_conf.h
并复制到lvgl
。将lv_conf.h
中的#if 0
更改为1从而激活该库中的内容。三个必须设置的基本参数为LV_HOR_RES_MAX
(显示屏水平像素最大值),LV_VER_RES_MAX
(显示屏垂直像素最大值)以及LV_COLOR_DEPTH
(显示屏颜色)4, 将
lvgl-master/lvgl.h
复制到需要调用LVGL
有关方程的位置5,调用
lv_tick_inc(x)
并为计时器或者任务设置一个x
毫秒的参数。此方程为LVGL
内部计时所必须。6,调用
lv_init()
7, 创建一个LVGL显示缓存。LVGL会将需要被更改的图形显示首先保存在这个缓存中再发送到前端更新画面。缓存的大小可以任选,屏幕尺寸的1/10是一个比较好的初始选择。
static lv_disp_buf_t disp_buf;//声明显示缓存数组
static lv_color_t buf[LV_HOR_RES_MAX * LV_VER_RES_MAX / 10];//设置尺寸为1/10屏幕大小的显示缓存
lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX / 10);//初始化显示缓存数组
8,接下来实现并注册一个方程将改变后的画面复制到显示屏的特定区域
lv_disp_drv_t disp_drv;/*创建显示驱动的报文数组*/
lv_disp_drv_init(&disp_drv);/*驱动基本初始化*/
disp_drv.flush_cb = my_disp_flush;/*设置驱动方程*/
disp_drv.buffer = &disp_buf;/*设置显示缓存*/
lv_disp_drv_register(&disp_drv);/*注册驱动*/
void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p){
int32_t x, y;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
set_pixel(x, y, *color_p);/* 在显示屏上放置一个像素*/
color_p++; }
}
lv_disp_flush_ready(disp
);/* 示意图像显示一切就绪*/}
9.在主函数
while(1)
,终端方程或操作系统任务中每数毫秒周期性调用lv_task_handler()
。
2,Widgets
控件 创建 布局:
图形界面元素包含按键,标签,滑块,图标等等。在LVGL中这些元素都是可以被调用的对象或者图标。
Widgets
章节有详细的对象列表。每一个对象都对应一个父对象。假设创立一个按键的标签,那么这个按键就是这个标签的父类。当父类被移动时,标签作为子类也会被移动。当父类被删除时标签也会被删除。
子类只有在父类上时才是可见的。换句话说,父类显示范围之外的子类都会被自动裁剪。
一个屏幕是一个根父类。你可以有任意数量的屏幕。当你需要调用当前的屏幕时,调用
lv_scr_act()
。使用lv_src_load(src1)
来加载屏幕显示。你可以使用
lv_<type>_create(parent,obj_to_copy)
来创建新的对象。这个方程会返回一个lv_obj_t*xxxx
的变量。以后再次调用该对象时则直接引用此变量名。在这个方程中,第一个参数是我们想创建对象的父类,第二个参数是则为我们希望复制的对象。如果未使用复制则设置为NULL
。
lv_obj_t * slider1 = lv_slider_create(lv_scr_act(), NULL);
使用
lv_obj_set_<parameters_name>(obj,<value>)
方程来为对象添加基本的属性
lv_obj_set_x(btn1, 30);//按键1的X轴位置
lv_obj_set_y(btn1, 10);//按键1的Y轴位置
lv_obj_set_size(btn1, 200, 50);//按键1的长宽尺寸
对象也可以有除了基本属性之外的对应其类别的特定属性,特定属性可以用
lv_<type>_set_<parameters_name>(obj,<value>)
方程来设置
lv_slider_set_value(slider1, 70, LV_ANIM_ON);//对滑块对象设置特殊属性,(滑块1,值70,动画开启)
前往对应的对象类别的库文件查阅完整的
API
手册,例如对应Widgets
下的滑块类则前往lvgl-master/src/lv_widgets/lv_slider.h
文件中查阅
3,回调事件
时间是当任意对象发生改变时用来通知用户的功能。你可以对一个对象设置一个
callback
方程来返回信息。比如当用户按下特定按键就调用这个callback
方程。以下是一个callback
方程的例子:
lv_obj_set_event_cb(btn, btn_event_cb); /*创建方程,将方程关联至特定按键*/
...
void btn_event_cb(lv_obj_t * btn, lv_event_t event){
//当按键被按下时打印Clicked,此处用法类似JavaScript
if(event == LV_EVENT_CLICKED) {
printf("Clicked\n"); }
}
4,部件
一个
Widgets
中可能包含多个部件。假设一个只有单一部件的按键叫做LV_BTN_PART_MAIN.
一个页面则有LV_PAGE_PART_BG ,LLV_PAGE_PART_SCROLLABLE, LV_PAGE_PART_SCROLLBAR
以及LV_PAGE_PART_FLASG
等多个部件这些不见可以是实体的,真是存在的对象,也可以是虚拟的比如滑动页面的功能就是一个虚拟的概念。
当你想对GUI设置风格或者对一个对象的某一个部件进行状态设置时,部件就扮演一个非常重要的角色。
5,状态
o LV_STATE_DEFAULT 普通,放开
o LV_STATE_CHECKED 按下或者勾选
o LV_STATE_FOCUSED 通过触摸屏,编码器,鼠标输入
o LV_STATE_EDITED 通过编码器编辑
o LV_STATE_HOVERED 鼠标防止于对象上
o LV_STATE_PRESSED 按下
o LV_STATE_DISABLED 关闭或未激活
例如当你按下一个对象时,对象会自动获得
LV_STATE_PRESSED
状态,当你放开这个对象时,这个状态会被移除。你可以使用
lv_object_state(obj,part)
来获得目标当前的状态。这个方程会返回一个OR状态。例如一个选项可能会返回多个可能的状态:
LV_STATE_CHECKED|LV_STATE_PRESSED|LV_STATE_FORUCED
6,风格
风格可以用来改变背景颜色,边框粗细,字体或者其他属性
风格是可以被叠加的,比如用
style_btn
来设施一个默认的按键样式,然后使用style_btn_red
来设定按键为红色设置每一个属性都关联一个特定的状态。例如你可以设置不同的背景颜色来关联
LV_STATE_DEFAULT
和LV_STATE_PRESSED
。LVGL
库会自动搜索能够匹配选定状态的最佳风格。例如一个对象在按下状态时如果有一个默认的边框设置或者用户设定的边框设置,那么这个设置就会被使用。有一些属性可以被继承,一般来说是文字相关的属性。也就是说如果子类的属性未被设置,那么对应父类的属性就会被用来定义子类的属性。比如你可以只对根父类也就是屏幕设置一次字体,之后所有这个屏幕下的对象都会使用这个字体。
本地风格也同样可以被赋予给对象
7,主题
主题是一系列默认的对象风格。当一个对象被建立时,主题会被自动添加给这个对象。
你可以从
lv_config.h
中选择要使用的主题
8, Micropython
# 创建一个标签与按键
scr = lv.obj()#当前屏幕
btn = lv.btn(scr)#在当前屏幕创建按键
btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)#按键对齐
label = lv.label(btn)#创建关联按键的标签
label.set_text("Button")#设置标签文字
# 加载显示
lv.scr_load(scr)
9,举例
1, 带标签的按键
#include "../../lv_examples.h"
//创建一个callback方程,之后会被下面的主程序调用
static void btn_event_cb(lv_obj_t * btn, lv_event_t event){
if(event == LV_EVENT_CLICKED) {
static uint8_t cnt = 0;
cnt++;
/*对按键的子类标签进行文字编辑*/
lv_obj_t * label = lv_obj_get_child(btn, NULL);
lv_label_set_text_fmt(label, "Button: %d", cnt);
}
}
/** * 创建一个有标签的按键并对其进行事件触发设定. */
void lv_ex_get_started_1(void){
lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL); /*在当前屏幕添加一个按键*/
lv_obj_set_pos(btn, 10, 10); /*设置按键的坐标*/
lv_obj_set_size(btn, 120, 50);/*设置按键的大小*/
lv_obj_set_event_cb(btn, btn_event_cb);/*关联一个callback到该按键*/
lv_obj_t * label = lv_label_create(btn, NULL); /*为该按键添加一个标签*/
lv_label_set_text(label, "Button");/*设置标签文字*/}
2, 设置按键风格
#include "../../lv_examples.h" /** * 从头开始创建按键风格属性 */
void lv_ex_get_started_2(void){
static lv_style_t style_btn;
static lv_style_t style_btn_red;
/*创建一个简易按键风格*/
lv_style_init(&style_btn);
lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10);
lv_style_set_bg_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_SILVER);
lv_style_set_bg_grad_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_GRAY);
lv_style_set_bg_grad_dir(&style_btn, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
/*改变按下状态的按键颜色*/
lv_style_set_bg_color(&style_btn, LV_STATE_PRESSED, LV_COLOR_GRAY);
lv_style_set_bg_grad_color(&style_btn, LV_STATE_PRESSED, LV_COLOR_SILVER);
/*添加按键边框*/
lv_style_set_border_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_border_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_70);
lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 2);
/*鼠标放置在按键上时改变按键边框颜色 */
lv_style_set_border_color(&style_btn, LV_STATE_FOCUSED, LV_COLOR_BLUE);
lv_style_set_border_color(&style_btn, LV_STATE_FOCUSED | LV_STATE_PRESSED, LV_COLOR_NAVY);
/*设置文字风格*/
lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE);
/*当按下时改变按键的大小*/
lv_style_set_transform_height(&style_btn, LV_STATE_PRESSED, -5);
lv_style_set_transform_width(&style_btn, LV_STATE_PRESSED, -10);
/*改变按键大小时添加一个转换效果*/
static lv_anim_path_t path;
lv_anim_path_init(&path);
lv_anim_path_set_cb(&path, lv_anim_path_overshoot);
lv_style_set_transition_prop_1(&style_btn, LV_STATE_DEFAULT, LV_STYLE_TRANSFORM_HEIGHT);
lv_style_set_transition_prop_2(&style_btn, LV_STATE_DEFAULT, LV_STYLE_TRANSFORM_WIDTH);
lv_style_set_transition_time(&style_btn, LV_STATE_DEFAULT, 300);
lv_style_set_transition_path(&style_btn, LV_STATE_DEFAULT, &path);
/*创建一个使用自定义风格的按键*/
lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL);/*在当前屏幕创建按键*/
lv_obj_set_pos(btn, 10, 10); /*设置按键XY坐标*/
lv_obj_set_size(btn, 120, 50);/*设置按键大小*/
lv_obj_reset_style_list(btn, LV_BTN_PART_MAIN); /*移除默认主题中的风格*/
lv_obj_add_style(btn, LV_BTN_PART_MAIN, &style_btn);
lv_obj_t * label = lv_label_create(btn, NULL); /*添加一个标签*/
lv_label_set_text(label, "Button"); /*添加标签文字*/
3, 滑块与定位
lv_obj_t * label;
//创建关联滑块的callback方程
static void slider_event_cb(lv_obj_t * slider, lv_event_t event){
//当滑块移动时,改变滑块标签显示的文字
if(event == LV_EVENT_VALUE_CHANGED) {
/*刷新文字*/
lv_label_set_text_fmt(label, "%d", lv_slider_get_value(slider));
}
}
/** * 创建一个滑块并将滑块当前状态读数显示为标签 */
void lv_ex_get_started_3(void){
/* 在显示屏中间创建一个滑块*/
lv_obj_t * slider = lv_slider_create(lv_scr_act(), NULL);
lv_obj_set_width(slider, 200);/*设置滑块宽度*/
lv_obj_align(slider, NULL, LV_ALIGN_CENTER, 0, 0); /*使滑块类与其父类(屏幕)中间对齐*/
lv_obj_set_event_cb(slider, slider_event_cb);/*关联滑块与callback方程*/
/* 在滑块下方创建一个标签 */
label = lv_label_create(lv_scr_act(), NULL);
lv_label_set_text(label, "0");
lv_obj_set_auto_realign(slider, true);/*在标签文字改变时保持中间对齐*/
lv_obj_align(label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);/*将标签中间对齐到滑块下方*/
}