03. LVGL的基本对象
一、LVGL的对象
1.1、LVGL的对象介绍
在 LVGL 中,用户界面的基本构建成分是对象,也称为小部件,例如:按钮、标签、图片、列表、图表、文本区域,等等。值得注意的是,LVGL 图形库虽然是由 C 语言开发的,但其所采用的是一种面对对象编程思维,这就涉及到了“类”的概念。在 C 语言中,并没有“类”的概念,而 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),具体的图层结构如下图所示:
在上述的图层中,活动屏幕层(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
(边框透明度):设置边框的透明度,如果透明度值为0
、LV_OPA_0
或LV_OPA_TRANSP
,则表示 对象边框完全透明;如果透明度值为255
、LV_OPA_100
或LV_OPA_COVER
,则表示 对象边框为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。border_width
(边框宽度):设置边框的宽度,该属性的单位只能是像素。border_side
(仅描绘一侧边框):用户可以仅描绘对象的某个边框,可选值:LV_BORDER_SIDE_NONE
、LV_BORDER_SIDE_TOP
、LV_BORDER_SIDE_BOTTOM
、LV_BORDER_SIDE_LEFT
、LV_BORDER_SIDE_RIGHT
、LV_BORDER_SIDE_INTERNAL
。
3.4.5、轮廓属性
对象的轮廓处于边框之外。
outline_width
(轮廓宽度属性):用户可以以像素为单位设置轮廓宽度。outline_color
(轮廓颜色属性):设置轮廓的颜色。outline_opa
(轮廓透明度属性):设置轮廓的透明度,如果透明度值为0
、LV_OPA_0
或LV_OPA_TRANSP
,则表示 对象轮廓完全透明;如果透明度值为255
、LV_OPA_100
或LV_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
(阴影透明度属性):设置阴影的透明度,如果透明度值为0
、LV_OPA_0
或LV_OPA_TRANSP
,则表示 对象阴影完全透明;如果透明度值为255
、LV_OPA_100
或LV_OPA_COVER
,则表示 对象阴影为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。
3.4.7、图片属性
仅图片相关的部件内容适用该属性。
img_opa
(图片透明度属性):设置图片的透明度,如果透明度值为0
、V_OPA_0
或LV_OPA_TRANSP
,则表示 图片完全透明;如果透明度值为255
、LV_OPA_100
或LV_OPA_COVER
,则表示 图片为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。img_recolor
(图片重新着色属性):用户可以设置一个颜色,将其混合到图片,这样可以使图片重新着色,相关的设置函数为lv_obj_set_style_img_recolor()
。仅设置图片的重新着色,我们将看不到任何效果,因为在默认的情况下,重新着色的透明度为 0,也就是完全透明的。img_recolor_opa
(图片重新着色透明度属性):设置图片重着色的强度,如果透明度值为0
、LV_OPA_0
和LV_OPA_TRANSP
,则表示 不混合颜色;如果透明度值为255
、LV_OPA_100
和LV_OPA_COVER
,则表示 图片完全重新着色。
3.4.8、线条属性
仅线条相关的部件或组成部分适用该属性。
line_width
(线的宽度属性):用户可以以像素为单位,设置线条的宽度**。line_rounded
(线条的端点属性):用户可以设置线条的端点形状,在相关的设置函数中,如果传入的参数为 true,则线条的端点为 圆角;如果传入的参数为 false,则线条的端点为 垂线。line_color
(线条的颜色属性):设置线条的颜色。line_opa
(线条的透明度属性):设置线条的透明度,如果透明度值为0
、LV_OPA_0
或LV_OPA_TRANSP
,则表示 线条完全透明;如果透明度值为255
、LV_OPA_100
或LV_OPA_COVER
,则表示 线条为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。
3.4.9、圆弧属性
仅圆弧相关的部件或组成部分适用该属性。
arc_width
(圆弧宽度属性):用户可以以像素为单位设置弧的宽度(厚度)。arc_rounded
(圆弧端点):用户可以设置圆弧的端点形状,在相关的设置函数中,如果传入的参数为 true,则圆弧的端点为 圆角;如果传入的参数为 false,则圆弧的端点为 直角。arc_color
(圆弧颜色属性):设置圆弧的颜色。arc_opa
(圆弧透明度属性):设置圆弧的透明度,如果透明度值为0
、LV_OPA_0
或LV_OPA_TRANSP
,则表示 圆弧完全透明;如果透明度值为255
、LV_OPA_100
或LV_OPA_COVER
,则表示 圆弧为不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。
3.4.10、文本属性
该属性适用于文本相关的部件或组成部分。
text_color
(文本颜色属性):设置文本的颜色。text_opa
(文本透明度属性):设置文本的透明度,如果透明度值为0
、LV_OPA_0
或LV_OPA_TRANSP
,则表示 文本完全透明;如果透明度值为255
、LV_OPA_100
或LV_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
(透明度):设置对象的透明度,如果透明度值为0
、LV_OPA_0
或LV_OPA_TRANSP
,则表示 对象完全透明;如果透明度值为255
、LV_OPA_100
或LV_OPA_COVER
,则表示对象为 不透明,用户可以根据需求,在 0 ~ 255 之间设置透明度的值。anim
(动画属性):使对象具有动画效果。anim_time
(动画时间属性):设置动画时间,该动画时间以毫秒为单位。anim_speed
(动画速度属性):设置动画速度,该动画速度以像素/秒为单位。layout
(布局属性):设置对象的布局,子元素将根据布局策略重新定位和调整大小。base_dir
(对象方向属性):设置对象的基本方向,可选值如下:LV_BIDI_DIR_LTR
、LV_BIDI_DIR_RTL
、LV_BIDI_DIR_AUTO
。
四、LVGL的事件
事件(Event)在 LVGL 中非常重要,它是连接用户 GUI 界面和硬件设备(例如 LED)之间的桥梁,我们可以将其理解为某种同类型操作动作的集合,例如,短按、长按、按下并释放、聚焦,等等。
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); // 获取传入的参数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具