lvgl入门学习第二篇lvgl基础对象

一、对象(lv_obj_t)

  1. LVGL采用面向对象的编程思想(OOP),她的基本构造块(类)是对象(实例),也就是我们所说的部件(Widgets)就是一个个部件,比如button、label、image等等

  2. lv_obj_t (类)定义了部件的抽象特点,其定义包含了数据的形式以及对数据的操作。部件(子类)比原本的类(称为父类或基类)要更加具体化,子类会继承父类的属性和行为。

  3. 在LVGL中,所有的对象都在 lv_obj_t 这个结构体的基础上进行演变,所以我们就看到了各种不一样的部件,就算是一样的部件,继承基础父类(基类)之后演变出来对象(实例)的形态或风格样式都不一样。

  4. 由于lvgl使用c语言编写,因此 lv_obj_t 只能通过结构体来表示,它并不是一个实例化后的类,因此我们需要先实例化出一个父类(lv_obj即基础对象)(基类),其他所有的部件(对象)都继承自这个父类(基类)。

具体逻辑关系如下图:
image

二、基础对象(lv_obj)

屏幕是没有父类的基础对象

2.1 屏幕对象的创建过程

lv_init
    _lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t)); // 初始化显示器链表
lv_disp_drv_register
    _lv_ll_ins_head(&LV_GC_ROOT(_lv_disp_ll)); 	// 注册显示器到链表
    disp->act_scr   = lv_obj_create(NULL);  	// 在显示器上创建一个默认屏幕
        lv_obj_class_create_obj
            obj->coords.x1 = 0;
            obj->coords.y1 = 0;
            obj->coords.x2 = lv_disp_get_hor_res(NULL) - 1; // 设置屏幕的水平宽度
            obj->coords.y2 = lv_disp_get_ver_res(NULL) - 1; // 设置屏幕的垂直高度

image

2.2 LVGL的三层屏幕

lv_scr_act(void); 	// 活动屏幕	disp->act_scr
lv_layer_top (void); 	// 顶层		disp->top_layer
lv_layer_sys (void);	// 系统层	 disp->sys_layer

image

韦东山视频讲解

三、基础对象的大小(size)

3.1 设置大小

设置宽度:lv_obj_set_width(obj, new_width);
设置高度:lv_obj_set_height(obj, new_height);

同时设置宽度、高度:lv_obj_set_size(obj, new_ width, new_ height);

3.2 获取大小

获取宽度:lv_obj_get_width(obj);
获取高度:lv_obj_get_height(obj);

四、基础对象的位置(Position)

4.1 LVGL屏幕的原点

  1. “笛卡尔坐标系”,又叫“直角坐标系”,学习数学的时候一般用这种坐标系。
  2. LVGL屏幕的坐标系,又称为“LCD坐标系”,他的原点位置和直角坐标系不一样。
  3. 确定了坐标系类型就确定了原点,确定了原点就可以设置和确定LVGL部件(对象)的位置。
  4. LVGL的原点位置在屏幕左上角

image
image

4.2 屏幕(部件区域)的表示

LVGL的原点位置在屏幕左上角
image

4.3 位置(Position)

4.3.1 设置位置(Set position)

设置x轴方向的坐标位置:lv_obj_set_x(obj, new_x);
设置y轴方向的坐标位置:lv_obj_set_y(obj, new_y);

同时设置x、y坐标位置:lv_obj_set_pos(obj, new_x, new_y);  // position

4.3.2 获取位置(Get position)

获取x轴坐标位置:lv_obj_get_x(obj);
获取y轴坐标位置:lv_obj_get_y(obj);

4.4 对齐(Alignment)

参照父对象对齐:lv_obj_set_align(obj, LV_ALIGN_...);

参照父对象对齐后再设置坐标位置:lv_obj_align(obj, LV_ALIGN_..., x, y);

参照另一个对象(无父子关系)对齐后设置坐标位置:lv_obj_align_to(obj_to_align, obj_referece, LV_ALIGN_..., x, y)

4.4.1 对齐类型(LV_ALIGN_...)

image

五、基础对象的盒子模型(border-box)

对象的“盒子”由以下部分构成:

边界(bounding):元素的宽度/高度围起来的区域(整个盒子)。
边框(border):边框有大小和颜色等属性(相当于盒子的厚度和它的颜色)。
填充(padding):对象两侧与其子对象之间的空间(盒子的填充物)。
内容(content):如果边界框按边框宽度和填充的大小缩小,则显示其大小的内容区域(盒子实际装东西的区域)。
轮廓(outline) :LVGL中没有外边距(margin)的概念(盒子之间的距离),确认代之的是轮廓(outline)。它是绘制于元素(盒子)周围的一条线,它不占据空间,位于边框边缘的外围,可起到突出元素(盒子)的作用。  例如:在浏览器里,当鼠标点击或使用Tab键让一个选项或者一个图片获得焦点的时候,这个元素就会多了一个轮廓框围绕 。

image

LVGL的盒子模型是理解对象(部件)的组成,修改对象的样式,实现对对象的布局、处理对象排列等的关键。


六、基础对象的样式(styles)

Styles 用于设置对象的外观。

  1. 样式是一个 lv_style_t 变量,可以保存边框宽度、文本颜色等属性。
  2. 将样式(变量)分配给对象就可以改变其外观。在赋值过程中,可以指定目标部分和目标状态
  3. 一个样式可以给多个对象使用(正常样式)
  4. 样式可以级联,就是将多个样式分配给一个对象。所以,我们不用将所有属性都在一个样式中指定,可以通过多个样式组合的形式指定。 LVGL 会优先使用我们定义的样式,如果没有就会使用默认值。
  5. 后来添加的样式具有更高的优先级。就是说如果在两种样式中指定了同一个属性,则将使用最后添加的样式。
  6. 如果对象中未指定某些属性(例如文本颜色),就会从父级继承。
  7. 对象的本地样式“正常”样式具有更高的优先级。
  8. 可以定义有过渡效果的样式。
  9. 默认有一个样式主题,可以自己定义样式主题,作为默认的样式主题使用。

6.1 初始化样式

样式存储在 lv_style_t 变量,样式变量应该是 静态 、全局或动态分配 的。不能是函数中的局部变量,因为当函数结束时它们会被销毁。样式初始化示例:

	static   lv_style_t   style_obj;
	lv_style_init(&style_obj);

6.2 设置样式属性

初始化好一个样式后就可以设置它的样式属性,接口函数如下格式:
lv_style_set_<property_name>(&style, <value>);

示例:
lv_style_set_bg_color(&style_obj, lv_color_hex(0x000000));   // 设置背景色
lv_style_set_bg_opa(&style_obj, LV_OPA_50);	                    // 设置背景透明度
lv_style_set_....

6.3 添加(应用)样式到对象

当初始化并且设置好一个样式后就可以将它添加到对象上面,接口函数只有一个:lv_obj_add_style(obj, &style, <selector>)

  • 参数 “obj” 就是要添加到的对象
  • “style” 是指向样式变量的指针
  • 是应添加样式的部分和状态的 OR-ed 值 (不能是互斥,否则就是清除标志,没法合并)。
示例:
lv_obj_add_style(obj, &style_obj, 0);  // 默认(常用)

lv_obj_add_style(obj, &style_obj, LV_STATE_PRESSED);  // 在对象被按下时应用样式

6.4 获取样式属性

获取属性的最终值(考虑级联、继承、本地样式和转换),接口函数如下格式:lv_obj_get_style_<property_name>(obj, <part>);

函数使用对象的当前状态,如果没有更好的候选对象,则返回默认值。

例如:
lv_color_t color = lv_obj_get_style_bg_color(obj, LV_PART_MAIN);

6.5 删除样式

删除对象的所有样式:lv_obj_remove_style_all(obj);
删除对象的特定样式:lv_obj_remove_style(obj, &style_obj, selector);
// 1、只有当 selector 与 lv_obj_add_style 中使用的 selector 匹配时,此函数才会删除 style
// 2、如果 style 是空,那么会根据给出的 selector 检查并删除所有匹配的样式
// 3、如果 selector 是 LV_STATE_ANY 或 LV_PART_ANY 就会删除具有任何状态或部分的样式。

6.6 查看样式属性

所有的可用的样式属性可以在文档或者代码中获取得到。
文档位置:

代码位置:

  • 普通样式:lvgl/src/misc/lv_style_gen.h
  • 本地样式:lvgl/src/core/lv_obj_style_gen.h

文档位置和代码位置在后续的版本更新中会发生变化,只供参考。

6.7 背景部分的属性

背景属性和盒子模型关系很大,背景属性主要有一下这些:

  • 背景(Background)
  • 边界(Border)
  • 轮廓(Outline)
  • 阴影(Shadow)
  • 填充(Padding)
  • 宽度和高度变换
  • X和Y变换

6.8 样式的状态和部分

对象可以处于以下状态的组合:

  • 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) 自定义状态

对象可以有 部分(parts) ,也可以有自己的样式。LVGL 中存在以下预定义部分

  • LV_PART_MAIN 类似矩形的背景
  • LV_PART_SCROLLBAR 滚动条
  • LV_PART_INDICATOR 指标,例如用于滑块、条、开关或复选框的勾选框
  • LV_PART_KNOB 像手柄一样可以抓取调整值
  • LV_PART_SELECTED 表示当前选择的选项或部分
  • LV_PART_ITEMS 如果小部件具有多个相似元素(例如表格单元格)
  • LV_PART_TICKS 刻度上的刻度,例如对于图表或仪表
  • LV_PART_CURSOR 标记一个特定的地方,例如文本区域或图表的光标
  • LV_PART_CUSTOM_FIRST 可以从这里添加自定义部件。

这些可能会随着lvgl的更新而不断增加,可以阅读最新版本的文档获取最新资料。


例如一个 滑杆(Slider) 包含三个部分:

  1. 背景
  2. 指标
  3. 旋钮

这意味着滑块的所有三个部分都可以有自己的样式

示例体验:http://lvgl.100ask.net/8.1/widgets/core/slider.html#slider-with-custom-style
默认状态如下:
image
调整滑杆如下:
image

6.9 本地样式

对象还可以存储在 本地样式(私有样式)

  • 本地样式不能在其他对象之间共享
  • 如果使用本地样式,将自动分配局部样式,并在删除对象时释放。
  • 本地样式对于向对象添加本地自定义很有用。

本地样式的接口函数的格式
lv_obj_set_style_<property_name>(obj, <value>, <selector>);

示例:
lv_obj_set_style_bg_color(obj,  lv_color_hex(0xffffff), 0);   // 设置背景色lv_obj_set_style_bg_opa(obj, LV_OPA_50, 0);	              // 设置背景透明度lv_style_set_style_....

删除本地样式的时候我们删除某一个样式:
lv_obj_remove_local_style_prop(obj, LV_STYLE_..., selector);
LV_STYLE_...的取值请看: lvgl/src/misc/lv_style.h 中的 lv_style_prop_t

6.10 样式继承

  1. 某些属性(通常与文本相关)可以从父对象的样式继承。
  2. 只有没有在为对象设置样式属性的时候,才应用继承。 在这种情况下,如果这个属性是可继承的,那这个属性的值会在父类中检索,直到一个对象为该属性指定了一个值。父类将使用自己的状态来确定该值。 因此,如果按下按钮,并且文本颜色来自此处,则将使用按下的文本颜色。

6.11 过渡特效

默认情况下,当一个对象改变状态(例如它被按下)时,新状态的新属性会立即设置但是,通过转换,可以在状态更改时播放动画。 例如,按下按钮时,其背景颜色可以在 300 毫秒内动画显示为按下的颜色。

Demo体验:
https://docs.lvgl.io/8.1/overview/style.html#transition
http://lvgl.100ask.net/8.1/overview/style.html#transition

6.12 样式主题

主题是风格的集合。如果存在活动主题,LVGL将其应用于每个创建的部件(对象)。 这将为UI提供一个默认外观,然后可以通过添加更多样式对其进行修改。

Demo体验:
https://docs.lvgl.io/8.1/overview/style.html#extending-the-current-theme
http://lvgl.100ask.net/8.1/overview/style.html#extending-the-current-theme

七、基础对象的事件(events)

1、什么是事件??

当发生用户可能感兴趣的事情时,LVGL 中会触发事件,例如当一个对象:

  • 被点击
  • 滚动
  • 数值改变
  • 重绘
  • 等等。。。

2、事件的处理

添加事件:lv_obj_add_event_cb(obj, event_cb, event_code, user_data);

发送事件:lv_event_send(obj, event_cb, event_code, user_data);

删除事件:

lv_obj_remove_event_cb(obj, event_cb);
lv_obj_remove_event_dsc(obj, event_dsc);    //event_dsc 是 lv_obj_add_event_cb 返回的指针

3、事件类型(event_code)[源码:lvgl/src/core/lv_event.h (lv_event_code_t)

]

4、事件回调函数的 lv_event_t 参数

  1. 事件回调函数只有一个参数,,现在的版本提供这些功能:
    static void my_event_cb(lv_event_t * event);
获取触发的事件代码:lv_event_code_t code = lv_event_get_code(e);
获取触发事件的对象:lv_obj_t * target = lv_event_get_target(e);
获取最初触发事件的对象(事件冒泡):lv_obj_t * target = lv_event_get_current_target(e);
获取事件传递的用户数据:
	获取使用 lv_obj_add_event_cb 传递的用户数据lv_event_get_param(e); 
	获取使用 lv_event_send 传递的用户数据
  1. 一个事件回调函数可给多个对象使用
  2. 一个对象可以使用多个事件回调函数
  3. 如果传入的用户数据不一样,一个对象可以绑定同一个事件回调函数多次,事件将按照添加的顺序调用。例如:
    lv_obj_add_event_cb(obj, my_clicked_event_cb, LV_EVENT_CLICKED, &num1);
    lv_obj_add_event_cb(obj, my_clicked_event_cb, LV_EVENT_CLICKED, &num2);

5、事件冒泡

如果对象启用了 lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE),该对象的所有事件将会发送到该对象的父级。如果父级也启用了 LV_OBJ_FLAG_EVENT_BUBBLE,那么事件继续发送到他的父级,依此类推。

lv_event_get_target(e); 获取触发事件的当前对象。
lv_event_get_current_target(e); 获取事件冒泡的父对象。
posted @ 2023-03-12 10:54  登云上人间  阅读(2728)  评论(0编辑  收藏  举报