03. LVGL的基本对象

一、LVGL的对象

1.1、LVGL的对象介绍

  在 LVGL 中,用户界面的基本构建成分是对象,也称为小部件,例如:按钮、标签、图片、列表、图表、文本区域,等等。值得注意的是,LVGL 图形库虽然是由 C 语言开发的,但其所采用的是一种面对对象编程思维,这就涉及到了“类”的概念。在 C 语言中,并没有“类”的概念,而 LVGL 通过结构体的形式实现了“类”的功能(并非真的“类”),具体的实现逻辑如下图所示:

LVGL实现类的逻辑

  由上图可知,在 LVGL 中,首先定义了 lv_obj_t 这个结构体,然后通过这个结构体去实例化一个基础对象(lv_obj),这个基础对象将作为父对象,去衍生更多的子对象(其它部件)。值得注意的是,通过这种“类”的方式去衍生其它部件,所衍生出来的部件将会继承父对象的一些基本属性,例如大小、位置、样式,等等,因此,我们可以通过一套统一的函数去管理不同部件的基本属性。

  在 LVGL 中,每个对象都有一些相同的基本属性,例如:大小、父类、样式、事件、位置。为了方便地设置基本属性,LVGL 设计了一套通用的属性设置函数,它们可以用于设置各个部件的基本属性。

1.2、创建对象与删除对象

  在 LVGL 中,用户可以在程序运行时动态创建或者删除一个对象。当对象被创建时,将消耗一定的内存,而当其被删除时,这部分内存将得到释放。

  LVGL 每个对象的创建函数都很类似,它们具有高度统一的风格,源码如下所示:

lv_obj_t * lv_<widget>_create(lv_obj_t * parent);

  在上述源码中,widget 代表的是不同的部件,例如开关(switch)、按钮(btn)、图片(img),等等。一般情况下,创建对象的函数只有一个形参,那就是 *parent,它指向父类,该父类可以是当前的活动屏幕(lv_scr_act)或者是其它的部件。

  用户需要删除一个对象,可使用以下几个函数:

lv_obj_del(lv_obj_t * obj);                                 // 立即删除一个对象,并该对象的子类一起删除
lv_obj_del_async(lv_obj_t * obj);                           // 下一次执行 lv_timer_handler 后删除对象
lv_obj_clean(lv_obj_t * obj);                               // 立刻删除一个对象的全部子类
lv_obj_del_delayed(lv_obj_t * obj, uint32_t delay_ms);      // 延时 delay_ms 毫秒再删除对象

1.3、LVGL的屏幕

  在 LVGL中,屏幕是没有父对象的特殊对象,要创建一个屏幕,可使用创建对象的方式:

lv_obj_t * scr1 = lv_obj_create(NULL);

  用户需要获取当前活动的屏幕,可以调用 lv_scr_act() 函数,其将返回指向活动屏幕的指针。在部件的创建中,我们经常会获取当前活动的屏幕,将其作为父类。

在默认的情况下,LVGL 初始化时,系统已经帮用户创建一个活动屏幕,不需要我们再次创建。

1.4、父对象与子对象的关系

  父对象可以视为子对象的容器,当子类被创建出来之后,它是在父对象里面的。注意:一个父对象可以拥有多个子对象,而子对象就只有一个父对象(屏幕除外)。父对象和子对象之间的关系如下:

  • 父对象移动,则子对象也会随着父对象移动。
  • 子对象移动,父对象并不会随之移动,如果子对象移动的位置超出父对象的范围,则超过的部分默认不可见。
  • 子对象在设置坐标位置时,坐标原点在父对象的左上角。

1.5、LVGL的图层

  在 LVGL 的工程中,一般拥有 3个图层,它们分别为 活动屏幕层(scr_act)、顶层(top)和 系统层(sys),具体的图层结构如下图所示:

LVGL图层结构

  在上述的图层中,活动屏幕层(scr_act)位于 最底下,在其之上是 顶层(top),而 最上面 则是 系统层(sys)。接下来,我们介绍各层的作用:

  • 活动屏幕层(scr_act):用户可以在该层创建各种部件,例如开关、按钮、进度条,等等。
  • 顶层(top):用户可在该层创建一些部件,例如一个菜单栏,一个弹出窗口等。如果系统的单击属性是启用的,则该层将吸收所有用户单击,这就类似于强制的弹窗提示,则用户必须处理完弹窗消息之后,才可以继续操作其它的内容。
  • 系统层(sys):该层的内容总是可见的,例如鼠标的光标。

  在 LVGL中,旧的对象将会被绘制在背景上,而新的对象则是绘制在前景上,换而言之,如果对象之间出现重叠,则后面创建的对象会覆盖前面的。当部件之间出现重叠时,用户可以根据需求来修改覆盖的情况,而 LVGL 为此提供了 3 个 相关的函数,具体如下所示:

static inline void lv_obj_move_foreground(lv_obj_t * obj);      // 将对象移动到前景
static inline void lv_obj_move_background(lv_obj_t * obj);      // 将对象移动到背景

二、LVGL的布局

  LVGL 的布局设计深受 CSS 启发,其主要内容涉及 3 个方面:坐标位置大小 以及 对齐方式

2.1、对象的坐标位置

  在 LVGL 中,我们可以通过如下函数设置对象的坐标位置:

void lv_obj_set_x(lv_obj_t * obj, int32_t x);                   // 设置对象 x 轴坐标
void lv_obj_set_y(lv_obj_t * obj, int32_t y);                   // 设置对象 y 轴坐标
void lv_obj_set_pos(lv_obj_t * obj, int32_t x, int32_t y);      // 设置对象 x,y 轴坐标

  用户可以直接设置设置具体的对象位置,具体的方式如下:

lv_obj_set_pos(obj, 10, 10);                                    // 设置对象 x,y 轴坐标

  用户也可以根据父类的区域大小,按百分比进行计算,此时可以使用 lv_pct() 函数将值转换为百分比,具体的方式如下:

lv_obj_set_pos(obj, lv_pct(10), lv_pct(10));                    // 设置对象 x,y 轴坐标

  当用户设置完对象位置之后,其值并不会立刻更新,如果此时获取对象的坐标,则获取回来的坐标值依旧是之前的。如果用户想让设置的坐标值立刻更新,可以调用 lv_obj_update_layout() 函数,该函数会强制 LVGL 重新计算坐标,刷新所有对象的位置和大小信息。

2.2、对象的大小

  在 LVGL 中,我们可以通过如下函数设置对象的大小:

void lv_obj_set_width(lv_obj_t * obj, int32_t w);                   // 设置对象的宽度
void lv_obj_set_height(lv_obj_t * obj, int32_t h);                  // 设置对象的高度
void lv_obj_set_size(lv_obj_t * obj, int32_t w, int32_t h);         // 设置对象的高度和宽度

  用户可以直接设置设置具体的对象大小,具体的方式如下:

lv_obj_set_size(obj, 200, 100);                                     // 设置对象的高度和宽度

  用户也可以根据父类的区域大小,按百分比进行计算,此时可以使用 lv_pct() 函数将值转换为百分比,具体的方式如下:

lv_obj_set_size(obj, lv_pct(100), lv_pct(100));                     // 设置对象的高度和宽度

2.3、对象的对齐

  在 LVGL 中,常用于设置对齐方式的函数有 3 个:

【1】、根据父对象的位置,居中对齐

static inline void lv_obj_center(lv_obj_t * obj);               // 根据父对象的位置,居中对齐

【2】、根据父对象的位置进行对齐

/**
 * @brief 根据父对象的位置进行对齐
 * 
 * @param obj 要对齐的对象
 * @param align 对齐的模式
 * @param x_ofs 要对齐后向 x 轴偏移量(以像素为单位)
 * @param y_ofs  要对齐后向 y 轴偏移量(以像素为单位)
 */
void lv_obj_align(lv_obj_t * obj, lv_align_t align, int32_t x_ofs, int32_t y_ofs);

  其中,对其方式的可选值如下:

enum _lv_align_t {
    LV_ALIGN_TOP_LEFT,                  // 顶部左边对齐
    LV_ALIGN_TOP_MID,                   // 顶部中间对齐
    LV_ALIGN_TOP_RIGHT,                 // 顶部右边对齐

    LV_ALIGN_BOTTOM_LEFT,               // 底部左边对齐
    LV_ALIGN_BOTTOM_MID,                // 底部中间对齐
    LV_ALIGN_BOTTOM_RIGHT,              // 底部右边对齐
  
    LV_ALIGN_LEFT_MID,                  // 左边中间对齐
    LV_ALIGN_RIGHT_MID,                 // 右边中间对齐
    LV_ALIGN_CENTER,                    // 中间对齐
};

根据父对象的位置进行对齐

【3】、根据另一个对象(无父子关系)的位置进行对齐

/**
 * @brief 根据另一个对象(无父子关系)的位置进行对齐
 * 
 * @param obj 要对齐的对象
 * @param base 向谁对齐
 * @param align 要对齐的模式
 * @param x_ofs 要对齐后向 x 轴偏移量
 * @param y_ofs 要对齐后向 y 轴偏移量
 */
void lv_obj_align_to(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, int32_t x_ofs, int32_t y_ofs);

  其中,对其方式的可选值如下:

enum _lv_align_t {
    LV_ALIGN_OUT_TOP_LEFT,              // 在外顶部左边对齐
    LV_ALIGN_OUT_TOP_MID,               // 在外顶部中间对齐
    LV_ALIGN_OUT_TOP_RIGHT,             // 在外顶部右边对齐

    LV_ALIGN_OUT_BOTTOM_LEFT,           // 在外底部左边对齐
    LV_ALIGN_OUT_BOTTOM_MID,            // 在外底部中间对齐
    LV_ALIGN_OUT_BOTTOM_RIGHT,          // 在外底部右边对齐

    LV_ALIGN_OUT_LEFT_TOP,              // 在外左边顶部对齐
    LV_ALIGN_OUT_LEFT_MID,              // 在外左边中间对齐
    LV_ALIGN_OUT_LEFT_BOTTOM,           // 在外左边底部对齐

    LV_ALIGN_OUT_RIGHT_TOP,             // 在外右边顶部对齐
    LV_ALIGN_OUT_RIGHT_MID,             // 在外右边中间对齐
    LV_ALIGN_OUT_RIGHT_BOTTOM,          // 在外右边底部对齐
};

根据另一个对象(无父子关系)的位置进行对齐

三、LVGL的样式属性

3.1、LVGL样式设置的方法

  在 LVGL 中,设置样式属性的方法有两个:

【1】、普通样式设置

  普通样式设置的最明显特点是:共用。它就类似于一个共用的样式套装,用户可以往里面添加所需要修改的样式内容(例如背景颜色、文本颜色等),当我们将这个样式套装应用到某个部件时,其所包含的样式内容将会被全部应用到该部件中。如果用户界面中有很多样式相同的部分,则建议使用此方法,这可以使样式设置变得非常高效。普通样式的具体设置流程,如下所示:

static lv_style_t style;                                        // 定义样式变量
lv_style_init(&style);                                          // 初始化样式

lv_style_set_bg_color(&style, lv_color_hex(0x115588));          // 设置背景
lv_style_set_bg_opa(&style, LV_OPA_50);                         // 设置背景透明度
lv_style_set_border_width(&style, 2);                           // 设置边框的宽度
lv_style_set_border_color(&style, lv_color_black());            // 设置边框的大小

lv_obj_t *obj1 = lv_obj_create(lv_scr_act());                   // 创建一个对象1
lv_obj_add_style(obj1, &style, LV_STATE_DEFAULT);               // 添加对象1的样式

lv_obj_t *obj2 = lv_obj_create(lv_scr_act());                   // 创建一个对象2
lv_obj_add_style(obj2, &style, LV_STATE_DEFAULT);               // 添加对象2的样式

  由上述代码可知,在设置普通样式时,用户需要先调用 lv_style_t 结构体,定义样式变量,然后初始化样式以及设置各种样式属性,最后即可为目标对象添加样式。如果其它对象需要使用已定义的样式变量对应的样式,则直接调用即可。

【2】、本地样式设置

  本地样式的特点是:设置简单,针对性强。当用户界面的对象样式有较大差异时,可以使用本地样式进行单独的设置,本地样式的具体设置流程如下:

lv_obj_t *obj = lv_obj_create(lv_scr_act());                        // 创建一个对象
lv_obj_set_style_bg_color(obj, lv_color_red(),LV_STATE_DEFAULT);    // 设置对象背景颜色

  由上述代码可知,本地样式的设置非常简单,只需要直接将样式设置到某个部件上即可,注意:在上述的 lv_obj_set_style_bg_color() 函数中,第三个形参代表“状态及组成部分选择器”,用户可以在此指定所设置的样式应用到哪一个组成部分,同时也可选择该样式在什么状态下生效。

样式属性的设置函数都是 lv_obj_set_style_xxx(本地样式)或者 lv_style_set_xxx(普通样式)的格式。

3.2、部件的组成部分

  在 LVGL 中,将一个复杂的部件分解成多个组成部分,这样我们即可单独地设置某个组成部分的样式。注意:如果用户想设置某个组成部分的样式,则需要在设置样式时选择该组成部分的对应枚举。各个组成部分对应的枚举如下表所示:

enum _lv_part_t {
    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_CURSOR       = 0x060000,        // 光标

    LV_PART_CUSTOM_FIRST = 0x080000,

    LV_PART_ANY          = 0x0F0000,
};

  这里,我们以进度条部件(Slider)为例,分析它的组成部分如下:

  • 主体背景(LV_PART_MAIN)
  • 指示器(LV_PART_INDICATOR)
  • 旋钮(LV_PART_KNOB)

进度条部件的组成部分

  由上图可知,进度条部件分为三个组成部分,所以我们在设置其样式时,直接指定某个组成部分,即可设置该部分的样式,示例代码如下:

lv_obj_t *slider = lv_slider_create(lv_scr_act());                              // 创建一个对象
lv_obj_set_style_bg_color(slider, lv_color_hex(0xff0000),LV_PART_INDICATOR);    // 设置指示器的背景颜色

3.3、部件的状态

  在 LVGL 中,所有的部件状态如下表所示:

enum _lv_state_t {
    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,     // 禁用状态
    LV_STATE_USER_1      =  0x1000,
    LV_STATE_USER_2      =  0x2000,
    LV_STATE_USER_3      =  0x4000,
    LV_STATE_USER_4      =  0x8000,

    LV_STATE_ANY = 0xFFFF,
};

  当用户需要添加或者清除部件的某个状态时,可以调用对应的函数,如下所示:

void lv_obj_add_state(lv_obj_t * obj, lv_state_t state);            // 添加状态

#define lv_obj_clear_state               lv_obj_remove_state
void lv_obj_remove_state(lv_obj_t * obj, lv_state_t state);         // 移除状态

  当用户设置部件样式时,可以指定该样式在哪一个状态下才生效,如下所示:

lv_obj_t * btn = lv_btn_create(lv_scr_act());                                   // 创建一个对象
lv_obj_set_style_bg_color(btn, lv_color_hex(0xff0000), LV_STATE_PRESSED);       // 设置按钮的背景颜色,按下时才生效

3.4、LVGL的样式属性

3.4.1、大小与位置属性

  • width(宽度):用户可以按像素单位、百分比或者 LV_SIZE_CONTENT(自适应)的方式设置宽度。使用百分比设置宽度时,是以父类的大小作为参考。
  • min_width(最小宽度):以像素或百分比为单位设置最小宽度。当对象设置最小宽度后,如果用户重新设置对象的宽度,且该宽度小于最小宽度时,将不会成功。
  • max_width(最大宽度):以像素或百分比为单位设置最大宽度。当对象设置最大宽度后,如果用户重新设置对象的宽度,且该宽度大于最大宽度时,将不会成功。
  • height(高度):用户可以按像素单位、百分比或者 LV_SIZE_CONTENT(自适应)的方式设置高度。使用百分比设置高度时,是以父类的大小作为参考。
  • min_height(最小高度):以像素或百分比为单位设置最小高度。当对象设置最小高度后,如果用户重新设置对象的高度,且该高度小于最小高度时,将不会成功。
  • max_height(最大高度):以像素或百分比为单位设置最大高度。当对象设置最大高度后,如果用户重新设置对象的高度,且该高度大于最大高度时,将不会成功。
  • x(X 坐标属性):设置对象的 X 轴位置(以父类为参考),以像素或百分比为单位。
  • y(Y 坐标属性):设置对象的 Y 轴位置(以父类为参考),以像素或百分比为单位。
  • align(对齐属性):设置对象的对齐属性
  • transform_width(变换宽度属性):使对象的两边变宽,以像素或百分比为单位。
  • transform_height(变换高度属性):使对象的两边变高,以像素或百分比为单位。
  • translate_x(X 轴坐标偏移属性):往 X 轴方向偏移,以像素或百分比为单位。
  • translate_y(Y 轴坐标偏移属性):往 Y 轴方向偏移,以像素或百分比为单位。
  • transform_zoom(缩放属性):用户可以调整图像的缩放,如果缩放值为 256,则表示 图像不缩放;如果缩放值为 128,则表示 图像大小为原来的 1/2;如果缩放值为 512,则表示 图像放大一倍
  • transform_angle(旋转属性):用户可以设置图像旋转角度旋转角度 = 旋转值 / 10

3.4.2、填充属性

  当部件之间存在父子关系时,用户可以在父对象和子对象之间设置填充,以改变子对象的布局,填充的方向如下图所示:

填充的方向

  • pad_top(顶部填充属性):当用户在父对象的顶部进行填充,子对象会向下偏移(相对父对象)。
  • pad_bottom(底部填充属性):当用户在父对象的底部进行填充,子对象会向上偏移(相对父对象)。
  • pad_left(左侧填充属性):当用户在父对象的左侧进行填充,子对象会向右偏移(相对父对象)。
  • pad_right(右边填充属性):当用户在父对象的右侧进行填充,子对象会向左偏移(相对父对象)。
  • pad_row(行之间填充属性):行之间的填充,由布局使用。
  • pad_column(列之间填充属性):列之间的填充,由布局使用。

3.4.3、背景属性

  • bg_color(背景颜色):设置对象的背景颜色
  • bg_opa(背景透明属性):设置背景的透明度,如果它的值为 0 LV_OPA_0 LV_OPA_TRANSP ,则表示 背景完全透明;如果值为 255 LV_OPA_100 LV_OPA_COVER,则表示 图像完全不透明;用户可以根据需求,在 0 ~ 255 之间设置透明度的值。
  • bg_grad_color(背景颜色渐变属性):设置背景的渐变颜色。当 grad_dir 属性设置为 LV_GRAD_DIR_NONE 时,渐变不会生效。
  • bg_grad_dir(背景渐变方向属性):设置背景的渐变方向,可选方向值为 LV_GRAD_DIR_NONE LV_GRAD_DIR_HOR LV_GRAD_DIR_VER
  • bg_grad_stop(背景渐变起点属性):设置背景渐变颜色的起始点,如果渐变起始点为 0,则表示渐变是从 顶部/左侧 开始;如果渐变起始点为 255,则表示渐变是从 底部/右侧 开始;如果渐变起始点为 128,则表示渐变是从 中心 开始。
  • bg_img_src(背景图片源属性):设置背景图像源,该图像源可从 lv_img_dsc_t 的指针(C 语言数组)、文件路径(例如外部 SD 卡)或内部的字体图标中获取。
  • bg_img_opa(背景图片透明度属性):设置背景图像的透明度,如果它的值为 0 LV_OPA_0 LV_OPA_TRANSP ,则表示 背景图像完全透明;如果值为 255 LV_OPA_100 LV_OPA_COVER,则表示 背景图像完全不透明;用户可以根据需求,在 0 ~ 255 之间设置透明度的值。
  • bg_img_recolor(背景图片重新着色属性):用户可以设置一个颜色,将其混合到背景图像,这样可以使图像重新着色,相关的设置函数为 lv_obj_set_style_bg_img_recolor()。仅设置背景图片的重新着色,我们将看不到任何效果,因为在默认的情况下,重新着色的透明度为 0,也就是完全透明的。
  • bg_img_recolor_opa(背景图片重新着色透明度属性):设置背景图像重着色的强度,如果透明度值为 0、LV_OPA_0和 LV_OPA_TRANSP,则表示不混合颜色;如果透明度值为 255、LV_OPA_100 和 LV_OPA_COVER,则表示背景图像完全重新着色。
  • bg_img_tiled(背景图片平铺属性):如果该属性启用,背景图像将被平铺

3.4.4、边框属性

  对象的边框处于主体之外,具体的示意图如下:

边框的位置

  • border_color(边框颜色):设置边框的颜色属性
  • border_opa(边框透明度):设置边框的透明度,如果透明度值为 0LV_OPA_0LV_OPA_TRANSP,则表示 对象边框完全透明;如果透明度值为 255LV_OPA_100LV_OPA_COVER,则表示 对象边框为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。
  • border_width(边框宽度):设置边框的宽度,该属性的单位只能是像素。
  • border_side(仅描绘一侧边框):用户可以仅描绘对象的某个边框,可选值:LV_BORDER_SIDE_NONELV_BORDER_SIDE_TOPLV_BORDER_SIDE_BOTTOMLV_BORDER_SIDE_LEFTLV_BORDER_SIDE_RIGHTLV_BORDER_SIDE_INTERNAL

3.4.5、轮廓属性

  对象的轮廓处于边框之外。

  • outline_width(轮廓宽度属性):用户可以以像素为单位设置轮廓宽度
  • outline_color(轮廓颜色属性):设置轮廓的颜色
  • outline_opa(轮廓透明度属性):设置轮廓的透明度,如果透明度值为 0LV_OPA_0LV_OPA_TRANSP,则表示 对象轮廓完全透明;如果透明度值为 255LV_OPA_100LV_OPA_COVER,则表示 对象轮廓为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。
  • outline_pad(轮廓间隙属性):设置轮廓线的填充,即对象主体和轮廓线之间的间隙。

3.4.6、阴影属性

  对象的阴影处于轮廓之外,具体的示意图如下:

阴影的位置

  • shadow_width(阴影宽度属性):用户可以以像素为单位设置阴影的宽度
  • shadow_ofs_x(阴影偏移 X 轴方向属性):设置阴影在 X 轴方向上的像素偏移量
  • shadow_ofs_y(阴影偏移 Y 轴方向属性):设置阴影在 Y 轴方向上的像素偏移量
  • shadow_color(阴影颜色属性):设置阴影的颜色
  • shadow_opa(阴影透明度属性):设置阴影的透明度,如果透明度值为 0LV_OPA_0LV_OPA_TRANSP,则表示 对象阴影完全透明;如果透明度值为 255LV_OPA_100LV_OPA_COVER,则表示 对象阴影为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。

3.4.7、图片属性

  仅图片相关的部件内容适用该属性。

  • img_opa(图片透明度属性):设置图片的透明度,如果透明度值为 0V_OPA_0LV_OPA_TRANSP ,则表示 图片完全透明;如果透明度值为 255LV_OPA_100LV_OPA_COVER,则表示 图片为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。
  • img_recolor(图片重新着色属性):用户可以设置一个颜色,将其混合到图片,这样可以使图片重新着色,相关的设置函数为 lv_obj_set_style_img_recolor()。仅设置图片的重新着色,我们将看不到任何效果,因为在默认的情况下,重新着色的透明度为 0,也就是完全透明的。
  • img_recolor_opa(图片重新着色透明度属性):设置图片重着色的强度,如果透明度值为 0LV_OPA_0LV_OPA_TRANSP,则表示 不混合颜色;如果透明度值为 255LV_OPA_100LV_OPA_COVER,则表示 图片完全重新着色

3.4.8、线条属性

  仅线条相关的部件或组成部分适用该属性。

  • line_width(线的宽度属性):用户可以以像素为单位,设置线条的宽度**。
  • line_rounded(线条的端点属性):用户可以设置线条的端点形状,在相关的设置函数中,如果传入的参数为 true,则线条的端点为 圆角;如果传入的参数为 false,则线条的端点为 垂线
  • line_color(线条的颜色属性):设置线条的颜色
  • line_opa(线条的透明度属性):设置线条的透明度,如果透明度值为 0LV_OPA_0LV_OPA_TRANSP,则表示 线条完全透明;如果透明度值为 255LV_OPA_100LV_OPA_COVER,则表示 线条为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。

3.4.9、圆弧属性

  仅圆弧相关的部件或组成部分适用该属性。

  • arc_width(圆弧宽度属性):用户可以以像素为单位设置弧的宽度(厚度)
  • arc_rounded(圆弧端点):用户可以设置圆弧的端点形状,在相关的设置函数中,如果传入的参数为 true,则圆弧的端点为 圆角;如果传入的参数为 false,则圆弧的端点为 直角
  • arc_color(圆弧颜色属性):设置圆弧的颜色
  • arc_opa(圆弧透明度属性):设置圆弧的透明度,如果透明度值为 0LV_OPA_0LV_OPA_TRANSP,则表示 圆弧完全透明;如果透明度值为 255LV_OPA_100LV_OPA_COVER,则表示 圆弧为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。

3.4.10、文本属性

  该属性适用于文本相关的部件或组成部分。

  • text_color(文本颜色属性):设置文本的颜色
  • text_opa(文本透明度属性):设置文本的透明度,如果透明度值为 0LV_OPA_0LV_OPA_TRANSP,则表示 文本完全透明;如果透明度值为 255LV_OPA_100LV_OPA_COVER,则表示 文本为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。
  • text_font(文本字体属性):用户可以根据需求设置文本的字体(包括自定义的字体)
  • text_letter_space(文本间隙属性):设置文本字符的间隙
  • text_decor(文本装饰属性):文本装饰,可选值如下: LV_TEXT_DECOR_NONE(正常文本)LV_TEXT_DECOR_UNDERLINE(下划线) 和 LV_TEXT_DECOR_STRIKETHROUGH(删除线)。
  • text_align(文本对齐属性):用户可以设置对象内的文本对齐。可选值如下:LV_TEXT_ALIGN_LEFT(对象内文本左对齐)、LV_TEXT_ALIGN_CENTER(对象内文本中间对齐)、LV_TEXT_ALIGN_RIGHT(对象内文本右对齐)、LV_TEXT_ALIGN_AUTO(对象内文本自动对齐)。

3.4.11、其它属性

  • radius(设置圆角的半径属性):用户可以设置对象边框的圆角半,如果圆角的 半径为 0,则对象边框圆角为 直角型;如果圆角的 半径大于 0且小于等于 LV_RADIUS_CIRCLE,则对象边框的圆角为 圆型(圆角的半径由设定值决定)。
  • opa(透明度):设置对象的透明度,如果透明度值为 0LV_OPA_0LV_OPA_TRANSP,则表示 对象完全透明;如果透明度值为 255LV_OPA_100LV_OPA_COVER,则表示对象为 不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。
  • anim(动画属性):使对象具有动画效果
  • anim_time(动画时间属性):设置动画时间,该动画时间以毫秒为单位。
  • anim_speed(动画速度属性):设置动画速度,该动画速度以像素/秒为单位。
  • layout(布局属性):设置对象的布局,子元素将根据布局策略重新定位和调整大小。
  • base_dir(对象方向属性):设置对象的基本方向,可选值如下:LV_BIDI_DIR_LTRLV_BIDI_DIR_RTLLV_BIDI_DIR_AUTO

四、LVGL的事件

  事件(Event)在 LVGL 中非常重要,它是连接用户 GUI 界面和硬件设备(例如 LED)之间的桥梁,我们可以将其理解为某种同类型操作动作的集合,例如,短按、长按、按下并释放、聚焦,等等。

  LVGL 的事件处理机制,能够监听事件,识别事件源,并完成事件处理,处理机制的示意图如下:

LVGL事件处理机制

  由上图可知,LVGL 的事件处理机制分为三部分:

  • 事件源,能够产生事件的部件,在 LVGL 中,每一个部件都可以触发事件。
  • 事件,用户对部件的操作动作,例如:短按、长按等。
  • 事件监听器,接收事件、解释事件并处理用户代码。

  在 LVGL 中,用户可以调用 lv_obj_add_event_cb() 函数来添加事件,其函数原型如下所示:

/**
 * @brief 添加事件
 * 
 * @param obj 指向对象的指针
 * @param event_cb 事件回调函数
 * @param filter 事件类型
 * @param user_data 用户数据
 * @return lv_event_dsc_t* 事件描述符
 */
lv_event_dsc_t * lv_obj_add_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb, lv_event_code_t filter, void * user_data);

  添加事件的如下:

// 第一步:创建按钮部件
lv_obj_t * btn = lv_btn_create(lv_scr_act());

// 第二步:添加事件并设置回调函数 
lv_obj_add_event_cb(btn, my_event_cb, LV_EVENT_CLICKED, NULL); 
static void my_event_cb(lv_event_t * event) 
{
    // 第三步:在回调函数中处理用户逻辑代码
    printf("Clicked\n");   
}

  用户还可以通过 lv_obj_remove_event_cb() 函数删除事件,其函数原型如下所示:

/**
 * @brief 删除事件
 * 
 * @param obj 指向对象的指针
 * @param event_cb 事件回调函数
 * @return true 有事件被移除
 * @return false 没有事件被移除
 */
bool lv_obj_remove_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb);

  事件类型可以理解为某种同类型操作动作的集合,例如短按、长按等,其可分为以下几类:① 输入设备事件;② 绘图事件;③ 其它事件;④ 特别事件;⑤ 自定义事件

  在 LVGL中,所有对象都可以接收输入设备事件、绘图事件和其它事件。

【1】、输入设备事件:主要描述触摸、按键等输入设备所触发的事件

typedef enum {
    /** Input device events*/
    LV_EVENT_PRESSED,             // 按下
    LV_EVENT_PRESSING,            // 连按
    LV_EVENT_PRESS_LOST,          // 对象仍被按下,但光标/手指滑离对象
    LV_EVENT_SHORT_CLICKED,       // 短按,滚动则不调用
    LV_EVENT_LONG_PRESSED,        // 长按,可指定长按时间 ,滚动则不调用
    LV_EVENT_LONG_PRESSED_REPEAT, // 长按,只调用一次。滚动则不调用
    LV_EVENT_CLICKED,             // 如果对象没有滚动(不管长按还是短按),则在释放时调用
    LV_EVENT_RELEASED,            // 每次释放对象时调用
    LV_EVENT_SCROLL_BEGIN,        // 滚动开始
    LV_EVENT_SCROLL_THROW_BEGIN,
    LV_EVENT_SCROLL_END,          // 滚动结束
    LV_EVENT_SCROLL,              // 发生滚动
    LV_EVENT_GESTURE,             // 检测到手势
    LV_EVENT_KEY,                 // KEY 被发送到对象,和按键输入设备有关
    LV_EVENT_ROTARY,              // 转动编码器或轮子
    LV_EVENT_FOCUSED,             // 被聚焦
    LV_EVENT_DEFOCUSED,           // 对象未聚焦
    LV_EVENT_LEAVE,               // 对象未聚焦,但被选中
    LV_EVENT_HIT_TEST,            // Perform advanced hit-testing
    LV_EVENT_INDEV_RESET,         // Indev has been reset
} lv_event_code_t;

【2】、绘图事件:主要描述部件绘画时的事件

typedef enum {
    /** Drawing events*/
    LV_EVENT_COVER_CHECK,        // 检查一个物体是否完全覆盖了一个区域
    LV_EVENT_REFR_EXT_DRAW_SIZE, // 获取对象周围所需的额外绘制区域,例如阴影
    LV_EVENT_DRAW_MAIN_BEGIN,    // 开始主要绘图阶段
    LV_EVENT_DRAW_MAIN,          // 执行主图
    LV_EVENT_DRAW_MAIN_END,      // 完成主要绘图阶段
    LV_EVENT_DRAW_POST_BEGIN,    // 开始绘制,当所有子类都被绘制时
    LV_EVENT_DRAW_POST,          // 执行绘制,当所有子类都被绘制时
    LV_EVENT_DRAW_POST_END,      // 完成后期绘制阶段,当所有子类都被绘制时
    LV_EVENT_DRAW_TASK_ADDED,    // Indev has been reset
} lv_event_code_t;

在部件绘画事件中,不能设置大小等属性,可以获取部件的属性。

【3】、其它事件:主要描述删除、大小、样式等事件

typedef enum {
    /** Other events*/
    LV_EVENT_CREATE,              // 正在创建对象
    LV_EVENT_DELETE,              // 正在删除对象
    LV_EVENT_CHILD_CHANGED,       // 子类被改变
    LV_EVENT_CHILD_CREATED,       // 子类被创造出来
    LV_EVENT_CHILD_DELETED,       // 子类被删除
    LV_EVENT_SCREEN_UNLOAD_START, // 屏幕卸载开始
    LV_EVENT_SCREEN_LOAD_START,   // 屏幕加载开始
    LV_EVENT_SCREEN_LOADED,       // 加载了一个屏幕
    LV_EVENT_SCREEN_UNLOADED,     // 卸载屏幕
    LV_EVENT_SIZE_CHANGED,        // 对象坐标/大小已更改
    LV_EVENT_STYLE_CHANGED,       // 对象的样式已更改
    LV_EVENT_LAYOUT_CHANGED,      // The children position has changed due to a layout recalculation
    LV_EVENT_GET_SELF_SIZE,       // 获取小部件的内部大小
} lv_event_code_t;

【4】、特别事件:主要描述对象数值被修改时触发的事件

typedef enum {
    /** Special events*/
    LV_EVENT_VALUE_CHANGED,       // 对象的值已更改
    LV_EVENT_INSERT,              // 文本被插入到对象中
    LV_EVENT_REFRESH,             // 通知对象刷新它上面的东西
    LV_EVENT_READY,               // 一个过程已经完成
    LV_EVENT_CANCEL,              // 一个进程已被取消
} lv_event_code_t;

【5】、自定义事件:自定义事件由用户添加,LVGL 从不发送自定义事件

  任何自定义事件代码都可通过以下方式注册:

uint32_t MY_EVENT_1 = lv_event_register_id();

  上述函数可将事件等级表的 ID 获取回来,然后调用 lv_event_send() 函数,发送事件到回调函数当中。

lv_result_t lv_event_send(lv_event_list_t * list, lv_event_t * e, bool preprocess);

  在 LVGL中,允许多个事件共用同一个回调函数,这可以大大减少回调函数的数量。LVGL 中提供了以下事件字段函数,用于获取事件相关的信息。

lv_event_code_t lv_event_get_code(lv_event_t * e);          // 获取事件类型代码,短按、滑动、长按等类型
void * lv_event_get_current_target(lv_event_t * e);         // 获取向其发送事件的对象,触发这个事件的对象
void * lv_event_get_target(lv_event_t * e);                 // 获取最初触发事件的对象
void * lv_event_get_user_data(lv_event_t * e);              // 获取用户数据
void * lv_event_get_param(lv_event_t * e);                  // 获取传入的参数
posted @   星光映梦  阅读(627)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示