" 名字取的这么花里胡哨是为了让大家尽可能的快速找到我,少走一些弯路。"
一、LVGL系列(一) 一文了解LVGL的学习路线 轻松了解LVGL的全部
二、LVGL系列(二)之一 LVGL必读介绍 为什么要学习LVGL
LVGL系列(二)之二 LVGL常见问题解答 整理自官方文档
二、LVGL系列(三)LVGL仿真环境的搭建(WIN下)
2.1 VS下搭建LVGL仿真环境
2.1 如何在仿真环境下运行自己的代码
三、LVGL系列(三) LVGL移植教程
四、LVGL系列(四)概述
4.1 对象 LVGL核心概念
4.2 位置、尺寸和布局
五、LVGL系列(五)部件
六、LVGL系列(六)布局
·“本文全部内容参考自LVGL官方文档,也可以说是官方文档的中文版。手翻版,水平有限,如有错误,还望指正”
阅读提醒:本文字多,喜欢看图的可能要失望了
此处待系列文章完成后会添加超链接跳转
阅读完本节您将了解到有关LVGL最重要的事情,通过阅读本节建立的大致印象,再去细读本系列的Porting(移植)和Overview(概述)部分将会事半功倍。
强烈建议大家先去在模拟器中开始LVGL的学习,而不是先去移植到开发板中。在没有了解个大概的情况下去移植只会浪费自己的宝贵时间。
LVGL已经被移植到很多IDE中了,从中选择你喜欢的IDE。在Simulators 可以获取到在适合你PC上运行的即用型工程。这个方式可以让你节省移植的时间,让你立即上手LVGL。
如果你想在你自己的工程中尝试LVGL,请按照下面的步骤来:
git clone https://github.com/lvgl/lvgl.git.
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf1[DISP_HOR_RES * DISP_VER_RES / 10];
/*Declare a buffer for 1/10 screen size*/
lv_disp_draw_buf_init(&draw_buf, buf1, NULL, MY_DISP_HOR_RES * MY_DISP_VER_SER / 10);
/*Initialize the display buffer.*/
3 static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
4 lv_disp_drv_init(&disp_drv); /*Basic initialization*/
5 disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/
6 disp_drv.buffer = &draw_buf; /*Assign the buffer to the display*/
7 disp_drv.hor_res = MY_DISP_HOR_RES; /*Set the horizontal resolution of the display*/
8 disp_drv.hor_res = MY_DISP_VER_RES; /*Set the verizontal resolution of the display*/
9 lv_disp_drv_register(&disp_drv); /*Finally register the driver*/
10 void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p) {
11 int32_t x, y;
12 /*It's a very slow but simple implementation.
13 *`set_pixel` needs to be written by you to a set pixel on the screen*/
14 for(y = area->y1; y <= area->y2; y++) {
15 for(x = area->x1; x <= area->x2; x++) {
16 set_pixel(x, y, *color_p);
17 color_p++;
18 }
19 }
20 lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/
21 }
23 static lv_indev_drv_t indev_drv; /*Descriptor of a input device driver*/
24 lv_indev_drv_init(&indev_drv); /*Basic initialization*/
25 indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/
26 indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/
27 lv_indev_drv_register(&indev_drv); /*Finally register the driver*/
28
29 bool my_touchpad_read(lv_indev_t * indev, lv_indev_data_t * data)
30 {
31 /*`touchpad_is_pressed` and `touchpad_get_xy` needs to be implemented by you*/
32 if(touchpad_is_pressed()) {
33 data->state = LV_INDEV_STATE_PRESSED;
34 touchpad_get_xy(&data->point.x, &data->point.y);
35 } else {
36 data->state = LV_INDEV_STATE_RELEASED;
37 }
38 }
39 bool my_touchpad_read(lv_indev_t * indev, lv_indev_data_t * data)
40 {
41 /*`touchpad_is_pressed` and `touchpad_get_xy` needs to be implemented by you*/
42 if(touchpad_is_pressed()) {
43 data->state = LV_INDEV_STATE_PRESSED;
44 touchpad_get_xy(&data->point.x, &data->point.y);
45 } else {
46 data->state = LV_INDEV_STATE_RELEASED;
47 }
48 }
更多的细节请参考Porting(移植)部分。
像按钮、滑块、标签、图表等图形化组件被称为对象或者窗口小部件,在文档的Widgets(小部件)可以找到可用小部件的全部列表。
每一个创建的对象都有一个它的父类。例如:如果在按钮上创建一个标签,那么按钮就是这个标签的父对象。
子对象随着父对象移动而移动,并且如果父对象被删除那么子对象也会被删除。
子对象只可以在父对象上可见,换句话说,子对象超出父对象的部分是被裁剪的或者说是被遮挡的。
屏幕对象是所有对象的根对象,你可以有任意数量的屏幕。
获取当前屏幕对象调用lv_scr_act() ,加载一个屏幕使用lv_scr_load(scr1).
你可以使用lv_<type>_create(parent)来创建一个新的对象,它会返回一个lv_obj_t * 型变量(句柄),可以通过这个句柄来设置新创建对象的参数。
For example:
lv_obj_t * slider1 = lv_slider_create(lv_scr_act());
可以使用函数 lv_obj_set_<parameter_name>(obj, <value>) 去设置一些基础属性。
For example:
lv_obj_set_x(btn1, 30);
lv_obj_set_y(btn1, 10);
lv_obj_set_size(btn1, 200, 50);
小部件有一些特定的参数可以通过lv_<widget_type>_set_<parameter_name>(obj,<value>)进行设置 。
For example:
lv_slider_set_value(slider1, 70, LV_ANIM_ON);
详细的API请阅读小部件部分的文档或者阅读相关的头文件 (e.g. lvgl/src/widgets/lv_slider.h).
事件用来通知用户对象发生了什么事情。你可以给一个对象绑定很多动作的回调函数,例如:点击、释放、拖拽、甚至被删除等。
回调函数是这样被分配的:
v_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED, NULL); /*Assign a callback␣to the button*/
...
void btn_event_cb(lv_event_t * e)
{
printf("Clicked\n");
}
也可以使用LV_EVENT_CLICKED LV_EVENT_ALL,以便对任何事件调用回调。
从 lv_event_t * e 当前事件的代码可以这样获取:
lv_event_code_t code = lv_event_get_code(e);
触发事件的对象可以被这样接受:
lv_obj_t * obj = lv_event_get_target(e);
要了解事件的所有功能,请转到Event overview部分。
widgets部件可以由一个或者多个零件构建而成。例如: 一个按钮只有一个零件组成 LV_PART_MAIN. 然而, 一个 Slider 滑块有 LV_PART_MAIN, LV_PART_INDICATOR and LV_PART_KNOB. 三个零件组成。
通过使用Parts 你能够在不同的零件使用不同的风格。(见下文)
要了解一个部件对象可以使用那个零件请阅读widgets 部分的文档。
对象可以处于以下状态组合中:
例如:如果按压一个对象,他将会自动的变成 LV_STATE_FOCUSED 和 LV_STATE_PRESSED 状态,而且当你释放它时,LV_STATE_PRESSED状态就会移除 。
去检查一个对象处于何种状态可以使用lv_obj_has_state(obj, LV_STATE_...).如果对象当时处于这个状态它会返回ture。
手动添加或者移除状态使用:
lv_obj_add_state(obj, LV_STATE_...);
lv_obj_clear_state(obj, LV_STATE_...);
Styles包含一些描绘对象外观的一些参数,例如:背景颜色、边框宽度、字体等内容。
风格对象是lv_style_t类型的变量,只有它们的指针被保存在对象中,因此它们应该是静态的或者是全局的。 在使用一个风格之前它需要被lv_style_init(&style1)方法初始化,然后再添加相关的属性.。
例如:
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));
样式可以指定给对象的零件和状态.例如:"按下滑块时在滑块上显示这种样式" :
lv_obj_add_style(slider1, &style1, LV_PART_INDICATOR | LV_STATE_PRESSED);
如果这个零件是LV_PART_MAIN,那么它将被省略:
lv_obj_add_style(btn1, &style1, LV_STATE_PRESSED); /*Equal to LV_PART_MAIN | LV_STATE_PRESSED*/
同样,也可以省略LV_STATE_DEFAULT:
lv_obj_add_style(slider1, &style1, LV_PART_INDICATOR); /*Equal to LV_PART_INDICATOR |␣LV_STATE_DEFAULT*/
对于LV_STATE_DEFAULT 和LV_PART_MAIN 可以简单的写0:
lv_obj_add_style(btn1, &style1, 0); /*Equal to LV_PART_MAIN | LV_STATE_DEFAULT*/
风格可以级联(与CSS相似)。 这意味着你可以给对象的某个零件添加更多的样式。
For example :style_btn 可以设置一个默认的外观,而style_btn_red能够覆盖背景颜色使按钮变成红色。
lv_obj_add_style(btn1, &style_btn, 0);
lv_obj_add_style(btn1, &style1_btn_red, 0);
如果未设置属性,则当前状态将使用LV_State_Default的样式。如果即使在默认状态下也未定义该属性,则使用默认值。
一些属性(通常相关的文本相关的属性)是可以被继承的。这意味着如果未在对象中设置属性,则它将在其父项中搜索。例如,您可以在屏幕的样式中设置字体,并且屏幕上的所有文本将默认继承。
本地样式属性也可以添加到对象中。它创建了一种驻留在对象内部的样式,其仅由对象使用:
lv_obj_set_style_bg_color(slider1, lv_color_hex(0x2080bb), LV_PART_INDICATOR | LV_STATE_PRESSED);
要了解样式的所有功能,请参阅Style overview部分。
主题是对象的默认样式。当对象创建时,主题的样式就自动的被应用到对象上了。
你可以在lv_conf.h里面选择主题。
带有一个标签并且在点击事件做出响应的按钮示例
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_BTN
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(e);
if(code == LV_EVENT_CLICKED)
{
static uint8_t cnt = 0;
cnt++;
/*Get the first child of the button which is the label and change its text*/
lv_obj_t * label = lv_obj_get_child(btn, 0);
lv_label_set_text_fmt(label, "Button: %d", cnt);
}
}
/** * Create a button with a label and react on click event. */
void lv_example_get_started_1(void) {
lv_obj_t * btn = lv_btn_create(lv_scr_act()); /*Add a button the current␣screen*/
lv_obj_set_pos(btn, 10, 10); /*Set its position*/
lv_obj_set_size(btn, 120, 50); /*Set its size*/
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL); /*Assign a␣callback to the button*/
lv_obj_t * label = lv_label_create(btn);/*Add a label to the button*/
lv_label_set_text(label, "Button"); /*Set the labels text*/
lv_obj_center(label);
}
#endif
从头为一个按钮创建一个样式
#include "../lv_examples.h"
#if LV_USE_BTN && LV_BUILD_EXAMPLES
static lv_style_t style_btn;
static lv_style_t style_btn_pressed;
static lv_style_t style_btn_red;
static lv_color_t darken(const lv_color_filter_dsc_t * dsc, lv_color_t color, lv_opa_t opa)
{
LV_UNUSED(dsc);
return lv_color_darken(color, opa);
}
static void style_init(void)
{
/*Create a simple button style*/
lv_style_init(&style_btn);
lv_style_set_radius(&style_btn, 10);
lv_style_set_bg_opa(&style_btn, LV_OPA_COVER);
lv_style_set_bg_color(&style_btn, lv_palette_lighten(LV_PALETTE_GREY, 3));
lv_style_set_bg_grad_color(&style_btn, lv_palette_main(LV_PALETTE_GREY));
lv_style_set_bg_grad_dir(&style_btn, LV_GRAD_DIR_VER);
lv_style_set_border_color(&style_btn, lv_color_black());
lv_style_set_border_opa(&style_btn, LV_OPA_20);
lv_style_set_border_width(&style_btn, 2);
lv_style_set_text_color(&style_btn, lv_color_black());
/*Create a style for the pressed state.
*Use a color filter to simply modify all colors in this state*/ static
lv_color_filter_dsc_t color_filter; lv_color_filter_dsc_init(&color_filter, darken);
lv_style_init(&style_btn_pressed);
lv_style_set_color_filter_dsc(&style_btn_pressed,&color_filter);
lv_style_set_color_filter_opa(&style_btn_pressed, LV_OPA_20);
/*Create a red style. Change only some colors.*/
lv_style_init(&style_btn_red);
lv_style_set_bg_color(&style_btn_red, lv_palette_main(LV_PALETTE_RED));
lv_style_set_bg_grad_color(&style_btn_red, lv_palette_lighten(LV_PALETTE_RED, 3));
}
/**
* Create styles from scratch for buttons.
*/
void lv_example_get_started_2(void)
{
/*Initialize the style*/
style_init();
/*Create a button and use the new styles*/
lv_obj_t * btn = lv_btn_create(lv_scr_act());
/* Remove the styles coming from the theme
* Note that size and position are also stored as style properties
* so lv_obj_remove_style_all will remove the set size and position too */
lv_obj_remove_style_all(btn);
lv_obj_set_pos(btn, 10, 10);
lv_obj_set_size(btn, 120, 50);
lv_obj_add_style(btn, &style_btn, 0);
lv_obj_add_style(btn, &style_btn_pressed, LV_STATE_PRESSED);
/*Add a label to the button*/
lv_obj_t * label = lv_label_create(btn);
lv_label_set_text(label, "Button");
lv_obj_center(label);
/*Create an other button and use the red style too*/
lv_obj_t * btn2 = lv_btn_create(lv_scr_act());
lv_obj_remove_style_all(btn2); /*Remove the styles coming␣from the theme*/
lv_obj_set_pos(btn2, 10, 80);
lv_obj_set_size(btn2, 120, 50);
lv_obj_add_style(btn2, &style_btn, 0);
lv_obj_add_style(btn2, &style_btn_red, 0);
lv_obj_add_style(btn2, &style_btn_pressed, LV_STATE_PRESSED);
lv_obj_set_style_radius(btn2, LV_RADIUS_CIRCLE, 0);
/*Add a local style too*/
label = lv_label_create(btn2);
lv_label_set_text(label, "Button 2");
lv_obj_center(label);
}
#endif
创建一个滑块并且将其值写到标签上。
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SLIDER
static lv_obj_t * label;
static void slider_event_cb(lv_event_t * e)
{
lv_obj_t * slider = lv_event_get_target(e);
/*Refresh the text*/
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); /*Align top of the slider*/
}
/* Create a slider and write its value on a label. */
void lv_example_get_started_3(void)
{
/*Create a slider in the center of the display*/
lv_obj_t * slider = lv_slider_create(lv_scr_act());
lv_obj_set_width(slider, 200); /*Set the width*/
lv_obj_center(slider);/*Align to the center the parent (screen)*/
lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL); /*Assign an event function*/
/*Create a label below the slider*/
label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "0");
lv_obj_align_to(label, slider, LV_ALIGN_OUT_TOP_MID, 0, -15);/*Align top of
the slider*/
}
#endif