4. 对象与基础属性:lv_obj_t的创建与销毁,位置、大小、对齐方式、父对象关系
好,我们进入第四章。这一章是整个LVGL的基石——对象。
你想想看,屏幕上任何一个按钮、一个标签、一个滑块,本质上都是什么?都是一个 lv_obj_t 结构体实例。说白了,LVGL里的一切都是对象。你学会了怎么摆弄这个对象,后面所有控件都是信手拈来。
4.1 对象的创建与销毁
先看创建。LVGL里创建一个对象,只需要一行代码:
lv_obj_t * btn = lv_obj_create(lv_scr_act());
这个 lv_obj_create() 函数接收一个参数——父对象指针。返回值是一个指向新对象的指针。
我刚开始用LVGL时,总觉得这玩意儿跟malloc一样要手动释放内存。其实不是。LVGL有自己的内存管理机制,但销毁对象时你确实需要主动调用:
lv_obj_del(btn);
调用完这行,btn指向的对象就被销毁了,内存也回收了。注意,销毁后不要再使用这个指针,否则就是野指针访问,大概率会硬故障。
如果你想延迟销毁,可以用 lv_obj_del_async(),它会在下一个LVGL心跳周期里安全地删除对象。适合在中断或回调里调用。
4.2 位置与大小
对象创建出来,默认在父对象的左上角,大小为100×100像素。但实际项目中,你肯定要调整。
设置大小:
lv_obj_set_size(btn, 120, 40);
设置位置:
lv_obj_set_pos(btn, 50, 30);
这两个函数分别设置对象的宽度/高度和x/y坐标。坐标是相对于父对象内容区域的左上角。
我个人习惯把位置和大小分开设置,这样代码更清晰。当然你也可以用 lv_obj_set_width()、lv_obj_set_height() 单独改一边。
lv_obj_set_size(btn, LV_PCT(100), LV_PCT(100))。LV_PCT宏表示百分比,非常实用。
4.3 对齐方式
手动算坐标太麻烦了。LVGL提供了对齐机制,让你轻松把对象放在父对象的某个位置。
最常用的对齐函数:
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0);
这行代码把btn居中放在父对象里。第三个和第四个参数是x和y的偏移量,单位是像素。
常用的对齐常量:
| 常量 | 含义 |
|---|---|
| LV_ALIGN_CENTER | 居中 |
| 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_obj_align_to(label, btn, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
这行代码把label放在btn的右侧中间,并且向右偏移10像素。非常适合做标签和输入框的布局。
lv_obj_set_align() 设置自动对齐标志,这样父对象变化时子对象会自动调整位置。
4.4 父对象关系
父对象关系是LVGL布局的核心。每个对象只能有一个父对象,但可以有多个子对象。父对象移动时,子对象跟着移动;父对象隐藏时,子对象也隐藏;父对象销毁时,所有子对象自动销毁。
获取父对象:
lv_obj_t * parent = lv_obj_get_parent(btn);
获取子对象列表:
uint32_t child_cnt = lv_obj_get_child_cnt(parent);
lv_obj_t * child = lv_obj_get_child(parent, 0); // 获取第一个子对象
改变父对象:
lv_obj_set_parent(btn, new_parent);
这个操作会把btn从当前父对象移除,添加到new_parent下。位置会保持相对屏幕不变,但坐标会重新计算。
4.5 知识体系图
下面这张图帮你理清本章的核心脉络:
4.6 综合示例
最后,我们写一个完整的例子,把今天学的都用上:
/* 创建父容器 */
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 300, 200);
lv_obj_align(cont, LV_ALIGN_CENTER, 0, 0);
/* 创建子按钮 */
lv_obj_t * btn = lv_obj_create(cont);
lv_obj_set_size(btn, 100, 40);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0);
/* 创建标签,放在按钮右侧 */
lv_obj_t * label = lv_obj_create(cont);
lv_obj_set_size(label, 80, 30);
lv_obj_align_to(label, btn, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
/* 3秒后销毁按钮 */
lv_timer_t * timer = lv_timer_create([](lv_timer_t * t) {
lv_obj_del((lv_obj_t *)t->user_data);
lv_timer_del(t);
}, 3000, btn);
这段代码创建了一个居中容器,里面放了一个居中按钮,按钮右侧10像素处放了一个标签。3秒后按钮自动销毁。
嗯,这一章的内容就到这里。对象的基础属性是LVGL的根基,后面所有控件都是在这个基础上扩展的。你把这些搞明白了,后面学控件就是水到渠成的事。