01_LVGL 对象与盒子模型详解
1. LVGL 的对象
在LVGL中,⽤⼾界⾯的 基本组成部分 是对象(控件),也称为 Widgets。例如,⼀个 按钮、标签、图像、列表、图表 或者 ⽂本区域。所有的对象都使⽤ lv_obj_t
指针作为句柄进⾏引⽤。之后可以使⽤该指针来设置或获取对象的属性。
1.1对象的属性
基础对象(控件) 实现了屏幕上控件的基本属性,例如:
- 坐标
- ⽗对象
- 基于⽗对象的后代
- 包含样式
- 诸如 Clickable*、*Scrollable 等属性。
在⾯向对象的思想中,基础对象 是 LVGL 中所有其他对象都继承的基类。
1.2 图层
LVGL具有图层概念,从顶层到底层依次是sys_layer
层、top_layer
层、act_scr
层,LVGL的三层屏幕显示优先级:
屏幕活动层(active screen) < 顶层(top layer) < 系统层(system layer)
top_layer
层及sys_layer
层用来创建一些随处可见的内容。
top_layer
层可以用来创建菜单栏,弹出窗口等…鼠标光标可以放在所有层的上面以确保它始终可见,也就是放在
sys_layer
层。一般都是在
act_scr
层创建各种控件(widgets),也就是objects对象。
lv_screen_active(void); // 活动屏幕(screen_active)
lv_layer_top(void); // 顶层(top layer)
lv_layer_sys(void); // 系统层(system layer)
// 可以在不同层上创建对象(控件)
lv_obj_create(lv_screen_active());
lv_obj_create(lv_layer_top());
lv_obj_create(lv_layer_sys());
2. LVGL 对象的⼤⼩
2.1 设置⼤⼩ (Set Size)
- 设置宽度:lv_obj_set_width(obj, new_width);
- 设置⾼度:lv_obj_set_height(obj, new_height);
- 同时设置宽度、⾼度:lv_obj_set_size(obj, new_width, new_height);
2.2 获取⼤⼩ (Get size)
- 获取实际宽度:lv_obj_get_width(obj);
- 获取实际⾼度:lv_obj_get_height(obj);
- 获取实际可⽤的宽度:lv_obj_get_content_width(obj);
- 获取实际可⽤的⾼度:lv_obj_get_content_height(obj);
- 获取实际可⽤的宽⾼区域:lv_obj_get_content_coords(obj);
3. LVGL对象的位置
3.1 LVGL 屏幕原点
我们常⻅的坐标系是“笛卡尔坐标系”,或者叫“直⻆坐标系”(坐标原点在左下⻆,⽔平向右为x轴正⽅向,竖直向上位y轴正⽅向**)。这种坐标系我们很熟悉,因为我们学习数学的时候⼀般就是使⽤这种坐标系。
而LVGL屏幕的坐标系和我们熟悉的坐标系不⼀样,LVGL的坐标系是我们⼀般称之为“LCD坐标系”,他的原点位置和直⻆坐标系的不⼀样(坐标原点在左上⻆,⽔平向右为x轴正⽅向,竖直向下为y轴正⽅向)。
屏幕区域的表⽰(假设屏幕是1024*600分辨率):
3.2 设置位置 (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);
3.3 设置对⻬ (Alignment)
- 参照⽗对象对⻬:lv_obj_set_align(obj, LV_ALIGN_…);
- 参照⽗对象对⻬后再设置坐标位置:lv_obj_align(obj, LV_ALIGN_…, x_ofs, y_ofs);
- 参 照 另 ⼀ 个 对 象 ( ⽆⽗⼦关 系 ) 对 ⻬ 后 设 置 坐 标 位 置 :lv_obj_align_to(obj_to_align, obj_referece,LV_ALIGN_…, x_ofs, y_ofs)
对⻬类型(LV_ALIGN_…):
子类设置对齐时,无法超出父类(含
OUT
修饰的关键字效果等同于无OUT
修饰)
3.4 获取位置 (Get Position)
-
获取x轴坐标位置(在⽗对象之内):
- lv_obj_get_x(obj); 提供原始的左上角坐标
- lv_obj_get_x2(obj); 提供右边界坐标
-
获取y轴坐标位置(在⽗对象之内):
- lv_obj_get_y(obj);
- lv_obj_get_y2(obj);
在 LVGL 中,每个对象都有一个由
lv_obj_t
表示的coords
字段,由左上角(x1, y1)和右下角(x2, y2)坐标组成,用于确定对象的位置和尺寸。这种设计使得计算宽度、高度、对齐和重叠检测变得简单直观。
- 获取x轴坐标位置(经过齐/平移的偏移量):lv_obj_get_x_aligned(obj);
- 获取y轴坐标位置(经过齐/平移的偏移量):lv_obj_get_y_aligned(obj);
若设置坐标之后没有该对象没有被操作过,那么需要lv_obj_update_layout();来更新目标的坐标值
lv_obj_get_x
返回对象在其父对象坐标系中的左上角 x 坐标,直接取自对象内部存储的coords.x1
值,是对象原始的 x 坐标。lv_obj_get_x2
返回对象右边界的 x 坐标,即对象的最右侧位置,通常等于coords.x2
。这个值代表对象占用区域的右端点,用于计算宽度(宽度 = x2 - x1)。lv_obj_get_x_aligned
返回对象经过对齐或样式调整后的“对齐” x 坐标。在 LVGL 中,对象可能会因布局、样式中设置的平移(translate)或其他对齐相关的属性而产生一个有效显示位置。该函数会计算并返回最终用于绘制和对齐的 x 坐标,而不仅仅是原始的coords.x1
。例如,如果对象在样式中设置了水平平移,其对齐坐标会反映这种偏移,使得对齐操作(如居中、右对齐)能基于调整后的位置进行计算。
4. 重点: 盒子模型
“盒子模型”在图形用户界面(GUI)开发中是一种将界面元素抽象为矩形区域(盒子)的设计思想。LVGL 以及许多其他 UI 框架都采用了这种模型。下面详细介绍盒子模型的核心概念.
据官方文档,盒子模型包含以下要素:
- 边界框(Boundary box)
- 表示对象本身的宽度和高度,即对象在父容器坐标系中所占用的矩形区域。
- 这个区域包含了边框(Border)和内容(Content)
- 边框宽度(Border width)
- 对象外侧环绕的一圈“边框”的厚度。
- 在 LVGL 中可以通过样式属性(如
border_width
)进行设置。 - 占用在边界框之内,也就是减去这部分后,才是对象的“可用区域”(内容区 + 内边距)。
- 内边距(Padding)
- 对象与其 子元素 之间的空白区域。
- 在 LVGL 的布局系统中,当对象内部需要留出一定空白时,就可以设置
padding_top
、padding_bottom
、padding_left
、padding_right
等。 - 只有当对象内部实际放置了子对象(例如一个按钮里有文字标签)时,这个内边距才会起作用,留出额外空间让子对象不紧贴边框。
- 外边距(Margin)
- 对象外部的空白区域。
- 仅被某些布局(如 Flex、Grid)考虑。也就是说,如果对象处于手动布局(绝对坐标)的状态,通常不会主动使用
margin
来计算位置;但在使用lv_obj_set_flex_flow()
或lv_obj_set_grid_dsc_array()
等布局时,margin
就会生效,用于在对象之间留出空隙。
- 内容(Content)
- 对象可用于绘制或放置子对象的“实际区域”。
- 从“边界框”中减去“边框宽度”和“内边距”后,剩余的区域即为内容区。
- 例如,如果边界框宽度为 300 px,边框厚度为 5 px,内边距为 30 px,则内容区的宽度 = 300 - 2×5 - 2×30 = 230 px。
放置子对象的“实际区域”。
- 从“边界框”中减去“边框宽度”和“内边距”后,剩余的区域即为内容区。
- 例如,如果边界框宽度为 300 px,边框厚度为 5 px,内边距为 30 px,则内容区的宽度 = 300 - 2×5 - 2×30 = 230 px。