对 lvgl 的通俗介绍

学习 lvgl 的理解总结,如有错误,麻烦各位大佬帮忙指正


目录

什么是 lvgl ?

部件的基本属性(所有部件都具备的属性)

一、大小

二、位置

三、样式

 1、有哪些样式

2、如何给部件添加样式

3、如何单独设置部件中某个部分的样式

四、事件

1、事件类型

2、事件回调函数


什么是 lvgl ?

lvgl 其实就是各种图形部件 Widget(如滑块、滚轮、按钮等)的集合库(GUI 库)。每个部件都是通过 API 函数创建(函数格式一般都是 lv_xxx_create( ),xxx 是部件名)。lv_obj_t 是部件类型,是结构体进行 typedef 后的重命名(可用来创建结构体或结构体指针,这个结构体内部具备所有部件的属性),因此,所有部件都具备一些共同属性,例如大小、颜色、位置、样式这些,只是不同部件其具体的参数可能不同

lvgl 采用了一定的面向对象编程的设计思想,我们操控的都是一个个别人事先为我们准备好编写好的部件(对象),如果想要使用部件,就得先创建部件需要调用部件创建函数(实例化),不像 C 是面向过程的编程,不管做什么都是从零开始(想使用部件也得从零开始编写出一个部件)。所有的对象都是在 lv_obj_t 这个结构体的基础上进行演变的,诞生各种不一样的部件

关于 lvgl 的屏幕

屏幕在 lvgl 中,是没有父类的基础对象,是 lvgl 初始化时就默认创建的部件,其他所有部件都是屏幕的衍生物(其他部件都继承于屏幕,屏幕是所有部件的父对象,准确说,屏幕是其他所有部件的最初父对象),如下:

ced8dae4cba441d9bd6053b1ab614322.png

Q:为什么说其他部件均继承于屏幕,或其他部件是屏幕的衍生物?

 

A:创建部件时,需要调用部件创建函数,部件创建函数有一个参数是 parent,即父对象,就是指定一个对象作为父对象,在父对象上创建生成一个部件,父对象是新部件的容器、是新部件的活动范围,没有父对象的话,新部件就无法出现(当然基础对象屏幕除外),如下:

lv_obj_t * obj1 = lv_obj_create(lv_scr_act()); //创建部件 obj1,父对象是屏幕
lv_obj_set_size(obj1, LV_PCT(40), LV_PCT(40)); //设置 obj1 的宽度、高度
lv_obj_align(obj1, LV_ALIGN_CENTER, 0, 0); //以父对象作为参照物进行居中

lv_obj_t * obj2 = lv_obj_create(obj1); //创建部件 obj2,父对象是 obj1
lv_obj_set_size(obj2, LV_PCT(20), LV_PCT(20)); //设置 obj2 的宽度、高度
lv_obj_align(obj2, LV_ALIGN_CENTER, 0, 0); //以父对象作为参照物进行居中

691da3e615544d57946655950a4a8561.png

可以看到,obj1 是在屏幕上创建的,位于屏幕内,也只能在屏幕内活动。obj2 是在 obj1 上创建的,位于 obj1 内,也只能在 obj1 内活动。

除屏幕外的所有部件,第一个创建的部件永远是以屏幕作为父对象才能被创建的。


部件的基本属性(所有部件都具备的属性)

一、大小

设置部件的宽度、高度的函数

lv_obj_set_width (obj, new_width)

设置 obj 部件的宽度

lv_obj_set_height (obj, new_height)

设置 obj 部件的高度

lv_obj_set_size (obj, new_ width, new_ height)

设置 obj 部件的宽度和高度

获取部件的宽度、高度的函数

lv_obj_get_width (obj)

获取 obj 部件的宽度

lv_obj_get_height(obj)

获取 obj 部件的高度


二、位置

我们常见的坐标系是“直角坐标系”,这是我们学习数学时都在使用的坐标系。LVGL 屏幕的坐标系和我们熟悉的坐标系不一样,LVGL 的坐标系称为“LCD 坐标系”,他的原点位置和直角坐标系的不一样,原点位置在屏幕左上角,两者区别如下图

daf7175e444144bcb2a123a3a08b1e0a.png

有了 LCD 坐标系,确认了原点位置,我们就可以此来设置部件的位置

设置 x y 轴位置函数

lv_obj_set_x (obj, new_x)

设置 obj 部件 x 轴方向的坐标位置

lv_obj_set_y (obj, new_y)

设置 obj 部件 y 轴方向的坐标位置

lv_obj_set_pos (obj, new_x, new_y)

同时设置 obj 部件 x、y 坐标位置

对齐函数(有不同的对齐模式)

lv_obj_set_align (obj, LV_ALIGN_...)

以父对象为参照物向中间对齐

lv_obj_align (obj, LV_ALIGN_..., x, y)

以父对象为参照物向中间对齐,并以对齐后的位置为原点再偏移 (x,y)

lv_obj_align_to (obj_to_align, obj_referece, LV_ALIGN_..., x, y)

以另一个对象 (无父子关系) 为参照物进行对齐,对齐后再偏移 (x,y)

对齐类型(即函数内的 LV_ALIGN_... 参数,根据 “...” 的不同,obj 会跑到类型指定位置)

440f34b243fa4ea0b10a5a6a62ab18bd.png


三、样式

样式,就是部件的外表属性,我们可以设置部件的样式,来达到优化显示界面实现用户交互

 

优化显示界面:

如下图按键中,如果发生重大事故,需要急停,明显右边的红色按钮更加明显好按。

5ed20f8587ef4a7cbdfe84e1211c79e3.png

 

实现用户交互:

就是你鼠标放到部件上后有反馈,部件有发生变化,让用户知道自己点下去了。

 1、有哪些样式

大小(Size)、位置(Position)、背景(Background)、轮廓(Outline)、边框(Border)、阴影(Shadow)、其他(Others)

2、如何给部件添加样式

1)普通样式(公共样式)

公有样式,创建后就放在那里,可以一直被调用,其他部件想用就调用样式添加函数即可。所有部件都能调用 lv_obj_add_style () 来添加样式。其中第二个参数作用:当部件处于什么状态时触发添加的样式,例如鼠标放在部件上后生效,或者是点击后生效,可选参数在下面会列举

添加公有样式的流程

1、定义样式变量:static  lv_style_t  style;(style名称可以用户自定义)
2、初始化样式:lv_style_init( &style );

3、添加公共样式:lv_style_set_xxx( &style,  <value> );(xxx是样式属性名,如下图列举一部分xxx) 

968841a33c594d38aec59af7cd29b85b.png

4、给部件添加样式:lv_obj_add_style( obj,  &style,  LV_STATE_zzz );(zzz是可选参数名)

 

程序示例(改变部件背景颜色)如下:

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);  /* 给部件添加样式 *

2)本地样式(私有样式)示例如下(改变部件背景颜色)

除了普通样式,还有本地样式,本地样式跟普通样式区别在于:本地样式不能跟其他对象间共享。如果使用本地样式,将自动分配局部样式,并在删除对象时释放。

添加本地样式的流程:
lv_obj_set_style_xxx (obj, <value>, LV_STATE_zzz );(zzz是可选参数名)

 

程序示例(改变部件背景颜色)如下:

lv_obj_t * obj = lv_obj_create(lv_scr_act());   /* 创建一个部件 */

lv_obj_set_style_bg_color(obj, lv_color_hex(0xf4b183),LV_STATE_DEFAULT);/* 给部件添加样式 */

3)参数 LV_STATE_zzz :决定了样式什么时候生效

enum {

    LV_STATE_DEFAULT             =  0x0000,         /* 默认状态 */

    LV_STATE_CHECKED             =  0x0001,       /* 切换或选中状态 */

    LV_STATE_FOCUSED             =  0x0002,       /* 通过键盘、编码器聚焦或通过触摸板、鼠标单击 */

    LV_STATE_FOCUS_KEY           =  0x0004,     /* 通过键盘、编码器聚焦 */

    LV_STATE_EDITED              =  0x0008,           /* 由编码器编辑 */

    LV_STATE_HOVERED             =  0x0010,       /* 鼠标悬停(现在不支持)*/

    LV_STATE_PRESSED             =  0x0020,        /* 已按下 */

    LV_STATE_SCROLLED            =  0x0040,       /* 滚动状态 */

    LV_STATE_DISABLED            =  0x0080,         /* 禁用状态 */

    …

};

 

4)边框和轮廓的区别

边框(border)是什么?

举例如下:

a、首先先创建一个部件:

8f0ab834db3d49c98ac9ef98a7860ca1.png

fb423db5663d445498aa6540d0d3eea8.png

b、给部件添加样式边框颜色

08fc840fbb764549950cc73054f91d04.png

c91d2848422d42b085677c18af3e8d2f.png

c、修改部件的样式边框的宽度

bdb27cca771748bfbe7ebef282325735.png

bd818cddbbf3460088e30e858875b61d.png

d、修改样式边框的透明度(值越小越透明,可设置值的范围 0~250)

aeb582cc7540412da8bb93a318dc6154.png

ea2468ac671e46aebd43e1148a3d1ea3.png

b4eb0af10dee4797b0a31ef69f61f44f.png

f23729acf1344bdd9bf1ea41f93542e5.png

 

轮廓(outline)是什么?

举例如下:(轮廓是在边框的外边)

6aa0caa162354d12988ceea9134d9f6b.png

a3759a19cd3842b2bb55c9775b9214c2.png

3、如何单独设置部件中某个部分的样式

例如,滑块部件是由三个部分组成,如下图

17463f3a693f42fea40e728bc58a5f52.png

 

lvgl 官方提供了下方枚举,提供给我们设置部件中某个部分的样式:

enum {

    LV_PART_MAIN                = 0x000000,                  /* 主体,像矩形一样的背景 */

    LV_PART_SCROLLBAR        = 0x010000,                  /* 滚动条 */

    LV_PART_INDICATOR        = 0x020000,                  /* 指示器,指示当前值 */

    LV_PART_KNOB                = 0x030000,                 /* 手柄或旋钮,用于调整参数值 */

    LV_PART_SELECTED        = 0x040000,                  /* 选项框,指示当前选择的选项 */

    LV_PART_ITEMS                = 0x050000,                  /* 相似的元素,例如单元格 */

    LV_PART_TICKS                = 0x060000,                  /* 刻度 */

    LV_PART_CURSOR                = 0x070000,                  /* 光标 */

};

 

使用举例:

a、首先先创建一个滑块

11983169855848ecbe1b4035a1909352.png

8ce81f5174e64b83a0d772db642a161f.png

b、给滑块部件添加背景颜色,注意:默认修改的是部件主体部分的颜色

9d7a9e202fee49468fe76be232fa64cc.png

b8301d052ec8470f8b8e272129db2576.png

c、修改滑块部件的手柄和指示器的背景颜色

5de3b5c201744f9fb0be353abeaa7602.png

968427b69754465d8fe6971a3a2bfb8f.png


四、事件

事件,就是我们触碰部件后,可以触发回调事件,执行事件回调函数,事件回调函数是用户自己编写的,有点类似中断,如下

258553d04a5a4a95a04033f043faf83d.png

想要触碰部件后能进入触发回调事件,需要先给部件加上事件,添加事件用到如下 API 函数

添加事件函数

lv_obj_add_event_cb (obj, event_cd, event_code, user_data);

参数

1、obj:要添加事件的部件

 

2、event_cd:事件回调函数,函数名自定义

 

3、event_code:事件类型(可以分为五类,如下)

 

4、user_data:用不到就设置为 NULL

删除事件函数

lv_obj_remove_event_cb (obj,  event_cb);

1、事件类型

事件类型分为 5 大类:

输入设备事件、绘图事件、自定义事件、特别活动、其他活动。

所有对象,如按钮、标签、滑块等等,无论事件类型如何,都会接收输入设备事件、绘图事件、其他事件。但特殊事件是特定于特定的小部件类型。自定义事件是由用户添加,不由 LVGL 发送。

具体详细参考 LVGL 官方文档资料:

如下是输入设备的部分事件类型:

531872dbb2dd4e19af6250e6e19e12cc.png

 

2、事件回调函数

格式:static void xxx ( lv_event_t *e ) { }  //xxx 是函数名,程序员自己任意定义

(1)不同的事件类型共用同一个事件回调函数时,不清楚是哪个事件类型触发了事件回调函数,这时该怎么解决才能区分是哪个事件类型触发的?解决方法如下,在事件回调函数内调用获取事件类型的函数,如下:

static void xxx( lv_event_t *e )

{

        lv_event_code_t   code = lv_event_get_code(e);                 /* 第一步:获取事件类型 */

        if ( code == LV_EVENT_CLICKED )                                 /* 第二步:判断事件类型 */

        {

                        printf(“事件类型: 按下后释放\r\n”);                          /* 第三步:执行相应操作 */

        }

        else if ( code == LV_EVENT_LONG_PRESSED)

        {

                        printf(“事件类型:按下(长按)\r\n”);        

        }

}

示例:

8448dbd3be3f47ef9cb3d1d1170ad96a.png

8ca276328e6c462c86370c914081b6bb.png

(2)不同的部件共用一个事件回调函数时,不清楚是哪个部件调用了事件回调函数,这时怎么处理才能知道触发事件回调时是哪个部件在触发?解决方法如下,在事件回调函数中调用获取触发事件部件的函数,如下:

static void xxx( lv_event_t *e )

{

        lv_obj_t   *target = lv_event_get_target(e);                 /* 第一步:获取触发事件的部件 */

        if ( target == parent_obj )                                 /* 第二步:判断触发事件的部件 */

        {

                        printf(“父对象触发事件 \r\n”);                          /* 第三步:执行相应操作 */

        }

        else if ( target == child_obj )

        {

                        printf(“子对象触发事件 \r\n”);        

        }

}

示例:

d606d26021e64cad8f9dc228032719f7.png

3cda585ae9b24000b48597939f413f8d.png

 

 

 

 

 

  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值