第一问
在 LVGL 8.2 中,lv_obj
和 lv_screen
是构建用户界面的核心基础对象,以下是它们的详细说明:
1. lv_obj
(基础对象)
- 定义:所有部件的基类,所有可见控件(如按钮、标签等)均继承自
lv_obj
。 - 作用:
- 容器功能:可作为容器嵌套其他部件(如按钮、标签),管理子对象的布局和样式。
- 基础属性:支持位置、大小、透明度、事件回调、样式(颜色、字体、边框等)等通用属性。
- 自定义控件:直接使用
lv_obj
可创建简单的自定义容器(如背景面板)。
- 示例代码:
lv_obj_t *parent = lv_obj_create(lv_scr_act()); // 创建父容器(基于当前屏幕) lv_obj_set_size(parent, 200, 150); // 设置大小 lv_obj_set_style_bg_color(parent, lv_palette_main(LV_PALETTE_BLUE), 0); // 设置背景颜色
2. lv_screen
(屏幕对象)
- 定义:根对象,代表一个完整界面(如手机屏幕或窗口),是其他部件的顶层父容器。
- 特性:
- 唯一性:每个
lv_screen
对象独立存在,无父对象(通过lv_scr_act()
获取当前活跃屏幕)。 - 多屏管理:可创建多个屏幕(如主界面、设置页),通过
lv_scr_load(screen)
切换显示。 - 默认行为:首次启动时,LVGL 自动创建默认屏幕(
lv_scr_act()
初始指向它)。
- 唯一性:每个
- 示例代码:
lv_obj_t *screen1 = lv_scr_act(); // 获取当前默认屏幕 lv_obj_t *screen2 = lv_obj_create(NULL); // 创建新屏幕(无父对象) lv_scr_load(screen2); // 切换到 screen2 lv_obj_t *label = lv_label_create(screen2); // 在 screen2 上添加标签 lv_label_set_text(label, "Hello Screen 2!");
关键区别
特性 | lv_obj | lv_screen |
---|---|---|
层级 | 所有部件的父类 | 根对象(无父对象) |
用途 | 通用容器或自定义控件的基础 | 管理完整界面(如多屏切换) |
创建方式 | lv_obj_create(parent) | lv_obj_create(NULL) 或默认屏幕 |
实际应用场景
lv_obj
:用于布局分组(如将按钮和标签打包到同一容器)、创建背景面板、实现自定义控件。lv_screen
:实现多界面切换(如主菜单→设置页→弹窗),每个屏幕独立管理子对象。
通过结合二者,可以高效构建复杂的交互界面。
第二问
多屏管理:可创建多个屏幕(如主界面、设置页),通过 lv_scr_load(screen) 切换显示。举例如下:
以下是一个通过按钮切换屏幕的完整示例代码:
#include "lvgl.h"
// 创建两个屏幕对象
lv_obj_t *screen1;
lv_obj_t *screen2;
// 点击按钮切换到 screen2 的回调函数
static void switch_to_screen2(lv_event_t *e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
lv_scr_load(screen2); // 加载 screen2
}
}
// 点击按钮切换回 screen1 的回调函数
static void switch_to_screen1(lv_event_t *e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
lv_scr_load(screen1); // 加载 screen1
}
}
void main() {
// 初始化 LVGL...
// 创建第一个屏幕(默认屏幕)
screen1 = lv_scr_act();
// 在 screen1 上添加按钮
lv_obj_t *btn1 = lv_btn_create(screen1);
lv_obj_set_pos(btn1, 50, 50); // 设置按钮位置
lv_obj_set_size(btn1, 120, 50); // 设置按钮大小
// 给按钮添加标签
lv_obj_t *label1 = lv_label_create(btn1);
lv_label_set_text(label1, "Go to Screen2");
// 绑定按钮点击事件
lv_obj_add_event_cb(btn1, switch_to_screen2, LV_EVENT_ALL, NULL);
// 创建第二个屏幕
screen2 = lv_obj_create(NULL); // 创建新屏幕(无父对象)
lv_obj_set_style_bg_color(screen2, lv_palette_main(LV_PALETTE_RED), 0); // 设置背景色
// 在 screen2 上添加返回按钮
lv_obj_t *btn2 = lv_btn_create(screen2);
lv_obj_set_pos(btn2, 50, 50);
lv_obj_set_size(btn2, 120, 50);
lv_obj_t *label2 = lv_label_create(btn2);
lv_label_set_text(label2, "Back to Screen1");
lv_obj_add_event_cb(btn2, switch_to_screen1, LV_EVENT_ALL, NULL);
}
代码说明
-
多屏初始化:
screen1
:通过lv_scr_act()
获取默认屏幕。screen2
:通过lv_obj_create(NULL)
创建独立的新屏幕。
-
屏幕切换逻辑:
- 点击
btn1
时,触发switch_to_screen2
回调,调用lv_scr_load(screen2)
切换到第二个屏幕。 - 点击
btn2
时,触发switch_to_screen1
回调,调用lv_scr_load(screen1)
返回第一个屏幕。
- 点击
-
视觉效果:
- 通过
lv_obj_set_style_bg_color
为screen2
设置红色背景(默认屏幕为黑色)。
- 通过
运行效果
- 初始显示
screen1
,有一个蓝色按钮(标签为 “Go to Screen2”)。 - 点击按钮后,切换到红色背景的
screen2
,显示返回按钮。 - 点击返回按钮后,回到初始的
screen1
。
关键 API
函数 | 作用 |
---|---|
lv_scr_act() | 获取当前活跃屏幕 |
lv_obj_create(NULL) | 创建一个无父对象的新屏幕 |
lv_scr_load(screen) | 切换到指定屏幕 |
实际开发中可根据需求调整屏幕布局和样式(如颜色、动画等)。
第三问
screen2 = lv_obj_create(NULL); //这个没有父对象,不会报错吗?解释如下
在 LVGL 中,screen2 = lv_obj_create(NULL);
不会报错,这是 LVGL 设计中的合法操作,原因如下:
1. 设计逻辑
- 根对象特性:当
lv_obj_create()
的父对象参数为NULL
时,LVGL 会将其视为新的屏幕对象(即根容器),而非普通子部件。 - 多屏机制:LVGL 允许同时存在多个屏幕(如主界面、设置页),每个屏幕都是独立的树状结构根节点,彼此无父子关系。
2. 对比普通对象
操作 | 结果 |
---|---|
lv_obj_create(NULL) | 创建新屏幕(根对象) |
lv_obj_create(parent) | 创建普通子对象(需有效父对象) |
3. 底层实现
- LVGL 内部会为
NULL
父对象的创建请求分配特殊标识,将其加入屏幕列表而非普通对象树。 - 切换屏幕时(
lv_scr_load()
),LVGL 会自动管理屏幕的显示/隐藏状态。
4. 示例验证
// 合法操作:创建两个屏幕
lv_obj_t *screen1 = lv_scr_act(); // 获取默认屏幕
lv_obj_t *screen2 = lv_obj_create(NULL); // 显式创建新屏幕(无父对象)
// 非法操作:普通对象必须指定父对象
lv_obj_t *child = lv_obj_create(NULL); // 错误!此对象既非屏幕也无所属父容器
lv_obj_t *valid_child = lv_obj_create(screen1); // 正确
5. 实际应用场景
- 多界面切换:如主界面、设置页、弹窗等独立屏幕。
- 动态屏幕管理:运行时按需创建/销毁屏幕(节省内存)。
总结
- ✅
lv_obj_create(NULL)
是 LVGL 创建新屏幕的标准方式,不会报错。 - ❌ 普通部件(非屏幕)必须指定有效的父对象,否则会导致未定义行为。
这种设计使 LVGL 的屏幕管理既灵活又高效,符合嵌入式 GUI 的资源约束需求。