LVGL对象

  1. LVGL中对象的基本概述
  • 基本概念

在LVGL中,对象(Object)是用户界面(UI)的最小组成单元,是一切可视化控件(如按钮、标签、滑块等)的抽象基类。它定义了控件的基础行为和通用属性(位置、尺寸、样式、事件等),并通过继承机制派生出各类具体控件,形成层次化的UI结构。

LVGL采用的是面向对象的编程思想,以抽象的类来实例化不同的对象(部件)。由于C语言中没有“类”的概念,LVGL以结构体的形式来实现“类”的思想。

  • 基础对象

基础对象(lv_obj)可以作为父对象,来创建其他对象,同时它也可作为部件(组件/控件)使用。

  • 对象创建

LVGL支持在运行时动态的创建对象,也就是说只有当前创建出来的对象才会消耗内存,比如某个场景下:用户准备点击按钮,点击按钮后需要显示一个新屏幕,则新屏幕不需要提前创建,而是点击按钮之后再创建即可。

LVGL提供了创建不同窗口组件的函数接口,这些函数的命名规则是lv_>_create(),并且创建组件的函数需要传入一个参数parent,这个参数指的是窗口组件的父类,如下图:

注意:创建窗口组件的函数的返回值尤其重要,是一个指向对象的句柄指针,指针类型是lv_obj_t *,利用该对象的句柄指针可以访问对象。

在LVGL提供的lvgl/src/widgets目录下的每个组件的头文件中都声明了用于创建组件的函数接口,大家可以根据需求来了解。

如下图所示,是一个常见的按钮,按钮上面有文字,所以用户可以选择创建一个按钮组件和一个标签组件,但是标签组件应该是跟随按钮组件的,所以按钮组件应该作为标签组件的父类。

  • 对象删除

窗口组件等对象创建出来之后会消耗内存,所以在不需要使用窗口组件的时候可以选择删除组件,LVGL提供了删除对象的函数接口,函数名称是lv_obj_del(),函数使用规则如下:

可以看到,该函数有一个参数,参数类型是指向待删除对象的句柄指针,但是要注意一点:调用该函数删除对象的时候会把该对象和该对象相关的子类一起删除。

  • 对象关系

刚才提到lv_obj_del()函数可以删除一个对象和该对象相关的子类,原因是LVGL中的对象之间是有依赖关系的。

可以看到LVGL官方文档中提到,除了屏幕之外,每个对象都有一个唯一的父对象,但是一个父对象可以有任意数量的子对象,并且父对象可以作为子对象的容器。

可以看到,按钮组件作为父对象,标签组件作为按钮组件的子对象,当用户删除按钮组件的时候,按钮的标签应该会一起删除才对。

  • 位移说明

按钮组件是在屏幕的某个位置显示的,而按钮上的标签组件则是附属于按钮组件的,所以当屏幕的按钮组件的位移发生变化时,和按钮相关的子对象也会相关发生位移变化,所以子对象的位移是相对于父对象的。

LVGL中所有对象以树状结构组织,形成父子关系,子对象继承父对象的坐标系统和样式属性,移动父对象时子对象自动跟随。

注意:如果父对象的部分子对象或者全部子对象脱离了父对象,则在外部是不可见的,也就是如果标签组件的父对象是按钮组件,那么只有在屏幕上的按钮组件上才可以看到该标签组件,如果标签组件脱离了按钮组件,那么在屏幕上也是看不到该标签组件的。

  • 创建屏幕

LVGL库中提供的窗口组件应该都是在屏幕上显示的,这里注意:屏幕并不是指显示设备以及显示设备的驱动,而是可以理解为“一块画布”,把组件都显示在“画布”上,然后把画布内容输出到帧缓冲设备。

另外,LVGL官方文档中提到屏幕(screen)属于特殊对象,屏幕对象( lv_scr_act() )作为根容器,管理所有可见对象。因为屏幕没有父对象,所以调用lv_obj_create(NULL)函数时参数为NULL即可,该函数使用规则如下:

注意:lv_obj_create()函数的返回值指的是被创建对象的句柄指针,后续操作该对象需要使用,记得接收!

另外,用户可以创建多个屏幕对象,但是显示器只有一个,也就意味着显示器只能显示一个屏幕,而正在显示的屏幕对象被称为活动屏幕。

可以看到,LVGL提供了两个关于屏幕操作的函数接口,lv_scr_act()用于获取当前活动屏幕,lv_screen_load()用于加载需要使用的新屏幕,注意:函数名称有变化,如下图:

可以看到,这两个函数接口都属于内联函数,两个内联函数内部都调用了相关的其他函数。

  • 基础练习
  1. 根据LVGL官网文档的移植流程,初始化Linux帧缓冲设备以及注册帧缓冲设备的驱动
  1. 根据LVGL官网文档提供的组件创建流程,创建一个屏幕并在屏幕上添加一个按钮组件

如果想要在显示器显示各种按钮组件,首先应该创建一块屏幕(screen)作为基础对象,其他的按钮组件应该在屏幕上进行布局设计,LVGL提供了创建屏幕的函数lv_obj_create(),由于LVGL中规定屏幕没有父对象,所以lv_obj_create()参数为NULL即可,代码如下:

按钮(button)属于LVGL的核心组件,但是和基础组件的使用规则一样,用户可以选择创建按钮组件并设置按钮组件的位置、大小等属性。

LVGL提供了关于按钮组件的头文件lv_btn.h和源文件lv_btn.c,其中包含了创建按钮组件的函数接口lv_btn_create(),使用规则如下:

可以看到,该函数需要传递参数,参数指的是按钮组件的父对象,由于按钮组件应该在屏幕显示,所以应该在当前活跃屏幕上显示按钮组件,也就是把当前活跃屏幕作为按钮组件的父对象,代码如下:

  1. 修改LVGL的文件(Makefile、lv_conf.h、lv_drv_conf.h),编译工程并下载到ARM开发板!

可以看到,在显示器的左上角出现按钮,由于没有设置按钮组件的相关属性,所以该按钮组件的属性是默认的。

  • 组件属性

在 LVGL中,组件(也称为对象或部件)是构建用户界面的基本单元。每个组件都有一些基本属性,包括大小(size)、位置(position)、对齐(alignment)、样式(styles)和事件(events)。

LVGL库中也提供了获取对象属性以及设置对象属性的函数接口,都声明在lv_obj.h头文件中

  1. 大小

在 LVGL 中,大小(Size) 是组件(对象)的基本属性之一,用于定义组件的宽度和高度。大小属性直接影响组件在屏幕上的显示区域,是布局和外观设计的基础。

LVGL中的lvgl/src/core目录下,提供和LVGL组件属性相关的源文件和头文件,其中在lv_obj_pos.h头文件中具有和组件的大小属性相关的函数接口,如下:

函数作用:设置宽度,以像素为单位

void lv_obj_set_width(lv_obj_t * obj, lv_coord_t width);

函数作用:设置高度,以像素为单位

void lv_obj_set_height(lv_obj_t * obj, lv_coord_t height);

函数作用:同时设置宽度和高度,以像素为单位

void lv_obj_set_size(lv_obj_t * obj, lv_coord_t width, lv_coord_t height);

函数作用:获取宽度,以像素为单位

lv_coord_t lv_obj_get_width(const lv_obj_t * obj);

函数作用:获取高度,以像素为单位

lv_coord_t lv_obj_get_height(const lv_obj_t * obj);

使用技巧:LVGL支持使用百分比设置组件大小,相对于父对象的大小,具体操作如下所示:

lv_obj_t * btn = lv_btn_create(lv_scr_act()); // 创建一个按钮

lv_obj_set_size(btn, LV_PCT(50), LV_PCT(50)); // 设置按钮大小为父对象的50%宽度和高度

使用技巧:某些组件可以设置为自适应大小,即根据内容自动调整大小,具体操作如下所示:

lv_obj_t * label = lv_label_create(lv_scr_act()); // 创建一个标签

lv_label_set_text(label, "Hello, LVGL!"); // 设置标签文本

lv_obj_set_width(label, LV_SIZE_CONTENT); // 设置宽度为自适应

lv_obj_set_height(label, LV_SIZE_CONTENT); // 设置高度为自适应

注意:组件的大小不能超过其父对象的大小,如果父对象的大小发生变化,子组件的大小可能需要重新调整。另外,如果当组件的内容(如文本)超出其大小,可能会被裁剪。用户可以通过调整大小或启用滚动来解决。

  1. 位置

在 LVGL中,位置(Position) 是组件(对象)的基本属性之一,用于定义组件在其父对象坐标系中的位置。位置属性决定了组件在屏幕上的显示位置,是布局和界面设计的关键。

LVGL 使用二维坐标系,原点 (0, 0) 位于父对象的左上角。水平方向为 X 轴,向右为正方向。垂直方向为 Y 轴,向下为正方向。位置值是一个 lv_coord_t 类型的整数,通常表示像素(px)。

LVGL中的lvgl/src/core目录下,提供和LVGL组件属性相关的源文件和头文件,其中在lv_obj_pos.h头文件中具有和组件的位置属性相关的函数接口,如下:

函数作用:设置X坐标,以像素为单位

void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x);

函数作用:设置Y坐标,以像素为单位

void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y);

函数作用:同时设置X和Y坐标,以像素为单位

void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y);

函数作用:获取X坐标,以像素为单位

lv_coord_t lv_obj_get_x(const lv_obj_t * obj);

函数作用:获取Y坐标,以像素为单位

lv_coord_t lv_obj_get_y(const lv_obj_t * obj);

使用技巧:LVGL支持使用百分比设置组件位置,相对于父对象的大小。具体操作如下所示:

lv_obj_t * btn = lv_btn_create(lv_scr_act()); // 创建一个按钮

lv_obj_set_pos(btn, LV_PCT(20), LV_PCT(30)); //按钮位置为父对象宽度的20%和高度的30%

使用技巧:LVGL可以使用lv_obj_align()或lv_obj_align_to()将组件对齐到父对象或其他对象。

lv_obj_t * btn = lv_btn_create(lv_scr_act()); // 创建一个按钮

lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0); // 将按钮居中对齐

lv_obj_t * label = lv_label_create(btn); // 在按钮上创建一个标签

lv_label_set_text(label, "Click Me!"); // 设置标签文本

lv_obj_align(label, LV_ALIGN_BOTTOM_MID, 0, 0); // 将标签对齐到按钮底部中间

注意:组件的位置是相对于其父对象的坐标系。如果父对象移动,子组件的位置也会随之变化。如果父对象的大小发生变化,子组件的位置可能需要重新调整。另外,组件的位置不能超出父对象的边界。如果超出,组件可能会被裁剪。

  1. 对齐

在 LVGL中,对齐(Alignment) 是组件(对象)的一个重要属性,用于将组件相对于其父对象或其他组件进行对齐。对齐属性可以帮助开发者快速实现复杂的布局,而无需手动计算坐标。

LVGL 提供了多种对齐方式,例如居中对齐、顶部对齐、底部对齐、左侧对齐、右侧对齐等,对齐方式通过 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 // 居中对齐

对齐可以基于父对象(默认)或其他组件,这种叫做对齐基准,另外在对齐时可以指定 X 和 Y 方向的偏移量,用于微调组件的位置。

对齐到父对象

void lv_obj_align(lv_obj_t * obj, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs);

对齐到其他对象

void lv_obj_align_to(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs);

使用技巧:LVGL支持将组件对齐到其父对象的某个位置。具体操作如下所示:

lv_obj_t * btn = lv_btn_create(lv_scr_act()); // 创建一个按钮

lv_obj_set_size(btn, 100, 50); // 设置按钮大小为 100x50

lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0); // 将按钮居中对齐

使用技巧:LVGL支持将一个组件对齐到另一个组件。具体操作如下所示:

lv_obj_t * btn1 = lv_btn_create(lv_scr_act()); // 创建按钮 1

lv_obj_set_size(btn1, 100, 50); // 设置按钮 1 大小为 100x50

lv_obj_align(btn1, LV_ALIGN_TOP_LEFT, 10, 10); // 将按钮 1 对齐到左上角,并偏移 (10, 10)

lv_obj_t * btn2 = lv_btn_create(lv_scr_act()); // 创建按钮 2

lv_obj_set_size(btn2, 80, 40); // 设置按钮 2 大小为 80x40

lv_obj_align_to(btn2, btn1, LV_ALIGN_OUT_BOTTOM_MID, 0, 10); // 将按钮 2 对齐到按钮 1 底部中间,并偏移 (0, 10)

使用技巧:LVGL支持在对齐时可以通过偏移量微调组件的位置。具体操作如下所示:

lv_obj_t * btn = lv_btn_create(lv_scr_act()); // 创建一个按钮

lv_obj_set_size(btn, 100, 50); // 设置按钮大小为 100x50

lv_obj_align(btn, LV_ALIGN_CENTER, 20, -10); // 将按钮居中对齐,并偏移 (20, -10)

注意:对齐是相对于父对象的坐标系。如果父对象移动或大小变化,对齐位置也会随之变化。另外,对齐时需确保组件不会超出父对象的边界。

练习:要求创建2个按钮,要求在LCD屏幕的看到2个按钮是类似于下图的结构,要对齐。

  1. 样式

在 LVGL 中,样式(Styles) 是组件(对象)的核心属性之一,用于定义组件的外观和视觉效果。样式可以控制组件的背景颜色、边框、字体、阴影、透明度等属性。通过样式,开发者可以轻松实现一致且美观的用户界面。

LVGL中的样式通过 lv_style_t 结构体表示,每个样式对象可以包含多个样式属性,并且样式对象可以被多个组件共享。

LVGL 提供了丰富的函数来设置样式属性,样式属性包括背景颜色、边框宽度、字体、文本颜色、阴影等,每个样式属性可以单独设置。

注意:LVGL中的样式对象需要用户手动初始化,但不需要手动释放(除非使用动态内存)。

函数作用:创建和初始化样式

lv_style_t style;

lv_style_init(&style);

函数作用:设置背景属性,例如设置背景颜色、透明度、渐变颜色和渐变方向。

void lv_style_set_bg_color(lv_style_t * style, lv_color_t value);

void lv_style_set_bg_opa(lv_style_t * style, lv_opa_t value);

void lv_style_set_bg_grad_color(lv_style_t * style, lv_color_t value);

void lv_style_set_bg_grad_dir(lv_style_t * style, lv_grad_dir_t value);

函数作用:设置边框属性,例如设置边框颜色、宽度、透明度和边框显示方向。

void lv_style_set_border_color(lv_style_t * style, lv_color_t value);

void lv_style_set_border_width(lv_style_t * style, lv_coord_t value);

void lv_style_set_border_opa(lv_style_t * style, lv_opa_t value);

void lv_style_set_border_side(lv_style_t * style, lv_border_side_t value);

函数作用:设置文本属性,例如设置文本颜色、字体和透明度。

void lv_style_set_text_color(lv_style_t * style, lv_color_t value);

void lv_style_set_text_font(lv_style_t * style, const lv_font_t * value);

void lv_style_set_text_opa(lv_style_t * style, lv_opa_t value);

函数作用:设置阴影属性,例如设置阴影颜色、宽度和偏移量。

void lv_style_set_shadow_color(lv_style_t * style, lv_color_t value);

void lv_style_set_shadow_width(lv_style_t * style, lv_coord_t value);

void lv_style_set_shadow_ofs_x(lv_style_t * style, lv_coord_t value);

void lv_style_set_shadow_ofs_y(lv_style_t * style, lv_coord_t value);

函数作用:设置阴影属性,例如设置阴影颜色、宽度和偏移量。

void lv_style_set_shadow_color(lv_style_t * style, lv_color_t value);

void lv_style_set_shadow_width(lv_style_t * style, lv_coord_t value);

void lv_style_set_shadow_ofs_x(lv_style_t * style, lv_coord_t value);

void lv_style_set_shadow_ofs_y(lv_style_t * style, lv_coord_t value);

把样式属性设置完成后,还需要把样式属性应用到组件对象上,LVGL也提供了对应的函数:

另外,LVGL也提供了把样式属性从组件对象上移除的的函数,函数使用规则具体如下所示:

void lv_obj_remove_style(lv_obj_t * obj, lv_style_t * style, lv_state_t state);

参数:

obj :目标组件(对象)。

style:样式对象。

state:组件状态(如 LV_STATE_DEFAULT、LV_STATE_PRESSED 等)。

注意:样式是有优先级的,如果多个样式应用于同一个组件,后应用的样式会覆盖先应用的样式。另外,样式可以针对不同的组件状态设置不同的属性,确保组件在不同状态下有正确的视觉效果。

  1. 事件

在 LVGL 中,事件(Events)是组件对象的核心属性之一,用于响应用户交互(如点击、拖动、输入等)或系统事件(如组件状态变化、动画完成等)。通过事件机制,开发者可以为组件绑定回调函数,实现交互逻辑。

LVGL 定义了多种事件类型(如点击、长按、拖动、焦点变化等),每个事件类型对应一个唯一的 lv_event_code_t 枚举值。并且开发者可以为组件注册事件回调函数,当事件触发时,回调函数会被调用。

LVGL中通过 lv_obj_add_event_cb() 函数为组件注册事件回调函数,函数使用规则如下所示:

函数原型:

void lv_obj_add_event_cb(

lv_obj_t * obj, // 目标组件

lv_event_cb_t event_cb, // 回调函数

lv_event_code_t filter, // 事件类型过滤器

void * user_data // 用户自定义数据(可选)

);

具体案例:

static void btn_event_cb(lv_event_t * e)

{

lv_event_code_t code = lv_event_get_code(e); // 获取事件类型

if (code == LV_EVENT_CLICKED)

{

printf("Button clicked!\n");

}

}

lv_obj_t * btn = lv_btn_create(lv_scr_act()); //创建按钮组件

lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED, NULL); // 注册点击事件回调

可以看到,事件的回调函数具有一个参数,类型是lv_event_t,lv_event_t 包含事件相关的所有信息,其中有几个关键字段较为常用:

  1. code:事件类型(lv_event_code_t)。
  2. target:触发事件的组件对象。
  3. current_target:当前处理事件的组件对象。
  4. user_data:注册事件回调时传递的自定义数据。

LVGL提供了相关函数来获取事件数据

lv_event_code_t code = lv_event_get_code(e); // 获取事件类型

lv_obj_t * obj = lv_event_get_target(e); // 获取触发事件的组件

void * user_data = lv_event_get_user_data(e); // 获取用户自定义数据

lv_area_t coords;

lv_indev_get_point(lv_indev_get_act(), &coords); // 获取触摸点坐标

注意:LVGL中事件是可以传播的,比如事件会从触发组件向上传播到其父对象,直到被处理或到达屏幕对象,这种传播方式被称为冒泡。并且可以通过返回值控制是否继续传播事件,这种方式被称为穿透。

在事件回调函数中,可以通过返回值控制事件传播:

LV_RES_OK:允许事件继续传播(默认)。

LV_RES_INV:阻止事件继续传播。

另外,LVGL库中的所有对象除了有相同基本属性外,不同类型的对象也有其自身特定属性,比如滑块对象就有最大值和最小值以及当前值等属性可以获取和设置,如下:

由于不同类型的对象拥有自身特定的属性,所以LVGL为不同类型的对象提供了不同的函数接口,用户可以在LVGL工程的widgets文件夹中找到相关组件的头文件进行查看,如下图:

作业:设计程序,要求在开发板的LCD屏幕上显示下图中的交互界面,要求用户可以输入手机号,当用户点击获取验证码的按钮时,要求利用HTTP协议向互亿无线服务器发送随机数作为验证码(提示:可以把电脑作为代码服务器),用户可以输入验证码,当用户点击登录按钮后,可以根据验证码是否正确,提示用户对应的信息。

提示:会使用文本框、按钮、标签、键盘,另外,标签目前是不可以显示汉字的,可以先使用英文代替内容。

提示:如果使用LVGL进行开发时,有控件不知道如何使用,则可以选择参考LVGL提供的关于控件的案例,控件的案例的路径都是在lvgl\examples\widgets目录下。如下:

想要使用案例的前提是在lv_conf.h头文件中启用宏定义,并在main.c中包含案例的头文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值