第2部分:基础构建篇 - 掌握UI的核心构建块
文章目录
- [**第2部分:基础构建篇 - 掌握UI的核心构建块**](#第2部分:基础构建篇 - 掌握UI的核心构建块)
-
- **第3章:LVGL的对象模型与核心概念**
-
- [**3.1 万物皆对象:理解LVGL的面向对象设计**](#3.1 万物皆对象:理解LVGL的面向对象设计)
- [**3.2 对象树:理解父子关系**](#3.2 对象树:理解父子关系)
- [**3.3 屏幕:对象的根容器**](#3.3 屏幕:对象的根容器)
- [**3.4 实战:创建你的第一个对象树**](#3.4 实战:创建你的第一个对象树)
- [**第4章:让界面"活"起来 - 样式系统入门**](#第4章:让界面"活"起来 - 样式系统入门)
-
- [**4.1 为什么需要样式系统?**](#4.1 为什么需要样式系统?)
- [**4.2 样式的数学模型**](#4.2 样式的数学模型)
- [**4.3 理解样式状态**](#4.3 理解样式状态)
- [**4.4 创建和应用样式**](#4.4 创建和应用样式)
- [**4.5 常用样式属性详解**](#4.5 常用样式属性详解)
- [**第5章:基础控件(一)- 标签、按钮与基础容器**](#第5章:基础控件(一)- 标签、按钮与基础容器)
-
- [**5.1 标签:文字的载体**](#5.1 标签:文字的载体)
- [**5.2 按钮:交互的基础**](#5.2 按钮:交互的基础)
- [**5.3 基础容器:布局的基石**](#5.3 基础容器:布局的基石)
- [**第6章:基础控件(二)- 滑块、开关、进度条**](#第6章:基础控件(二)- 滑块、开关、进度条)
-
- [**6.1 滑块:精确的数值输入**](#6.1 滑块:精确的数值输入)
- [**6.2 开关:二进制状态选择**](#6.2 开关:二进制状态选择)
- [**6.3 进度条:操作反馈与状态显示**](#6.3 进度条:操作反馈与状态显示)
- [**6.4 综合实战:创建简易调光器界面**](#6.4 综合实战:创建简易调光器界面)
- **本章总结与挑战**
第3章:LVGL的对象模型与核心概念
3.1 万物皆对象:理解LVGL的面向对象设计
在LVGL中,一切可视元素都是对象。按钮是对象,标签是对象,屏幕本身也是一个对象。这种统一的对象模型带来了极大的灵活性和一致性。
从面向对象的角度看,LVGL实现了一个继承体系:
<<核心对象>> lv_obj_t -type -parent -children -style_list -event_cb +coords +... lv_label -text +set_text() +get_text() lv_button +... lv_slider -value +set_value() +get_value()
所有控件都继承自基础对象 lv_obj_t
,这意味着:
- 所有对象都有共同的基本属性(位置、大小、父对象等)
- 所有对象都支持共同的操作(创建、删除、移动、设置样式等)
- 每个派生对象添加自己特有的功能(如标签的文本、滑块的数值)
3.2 对象树:理解父子关系
LVGL通过父子关系构建了一个对象树结构,这决定了:
- 渲染顺序:父对象先渲染,子对象后渲染
- 坐标系统:子对象的坐标相对于父对象
- 可见性:如果父对象不可见,所有子对象都不可见
- 生命周期:删除父对象会自动删除所有子对象
对象树示例:
屏幕 lv_scr_act 容器 Container 按钮 Button 标签 Label 1 标签 Label 2 按钮内标签
3.3 屏幕:对象的根容器
屏幕是对象树的根节点。每个LVGL应用至少有一个屏幕:
c
/* 获取当前活动屏幕 */
lv_obj_t * screen = lv_scr_act();
/* 创建新的屏幕 */
lv_obj_t * new_screen = lv_obj_create(NULL);
/* 切换到新屏幕 */
lv_scr_load(new_screen);
3.4 实战:创建你的第一个对象树
让我们通过代码来理解这些概念:
cpp
#include <lvgl.h>
#include <lv_drivers/display/monitor.h>
#include <lv_drivers/indev/mouse.h>
#include <stdlib.h>
// ... 省略初始化代码(与第一部分相同)
int main(void) {
// LVGL初始化(省略,参考第一部分)
/********************
* 创建对象树
********************/
// 获取当前活动屏幕
lv_obj_t * screen = lv_scr_act();
// 1. 创建一个容器作为父对象
lv_obj_t * container = lv_obj_create(screen);
lv_obj_set_size(container, 200, 150); // 设置大小
lv_obj_set_pos(container, 50, 50); // 设置位置
lv_obj_set_style_bg_color(container, lv_color_hex(0xE0E0E0), 0); // 浅灰色背景
// 2. 在容器内创建标签(子对象)
lv_obj_t * label1 = lv_label_create(container);
lv_label_set_text(label1, "子标签 1");
lv_obj_set_pos(label1, 10, 10); // 相对于容器的位置
// 3. 在容器内创建另一个标签
lv_obj_t * label2 = lv_label_create(container);
lv_label_set_text(label2, "子标签 2");
lv_obj_set_pos(label2, 10, 40);
// 4. 直接在屏幕上创建按钮(屏幕的子对象)
lv_obj_t * button = lv_btn_create(screen);
lv_obj_set_size(button, 120, 50);
lv_obj_set_pos(button, 300, 50);
// 5. 在按钮内创建标签(按钮的子对象)
lv_obj_t * btn_label = lv_label_create(button);
lv_label_set_text(btn_label, "按钮");
lv_obj_center(btn_label);
// 主循环(省略)
while(1) {
lv_timer_handler();
SDL_Delay(5);
}
return 0;
}
关键API解析:
lv_xxx_create(parent)
- 创建对象,指定父对象lv_obj_set_size(obj, width, height)
- 设置对象大小lv_obj_set_pos(obj, x, y)
- 设置对象位置lv_obj_center(obj)
- 让对象在父对象中居中
第4章:让界面"活"起来 - 样式系统入门
4.1 为什么需要样式系统?
样式系统让UI设计实现了内容与表现的分离。想象一下,如果没有样式系统,你要修改应用中所有按钮的颜色,就需要遍历每个按钮逐一设置。有了样式系统,你只需要修改样式定义,所有使用该样式的按钮都会自动更新。
4.2 样式的数学模型
在LVGL中,样式可以被看作一个从状态空间 到视觉属性的映射函数:
设:
- S = { s 1 , s 2 , . . . , s n } S = \{s_1, s_2, ..., s_n\} S={s1,s2,...,sn} 是对象的所有可能状态集合
- A = { a 1 , a 2 , . . . , a m } A = \{a_1, a_2, ..., a_m\} A={a1,a2,...,am} 是所有可设置的视觉属性集合
那么样式函数 f f f 定义为:
f : S → A f: S \rightarrow A f:S→A
对于每个状态 s i s_i si,样式系统返回对应的属性集合 A i A_i Ai。
4.3 理解样式状态
LVGL对象可以同时处于多个状态,常见状态包括:
状态 | 描述 | 触发条件 |
---|---|---|
LV_STATE_DEFAULT |
默认状态 | 对象创建时的初始状态 |
LV_STATE_PRESSED |
按下状态 | 对象被点击或触摸时 |
LV_STATE_FOCUSED |
获得焦点 | 通过键盘或编码器导航时 |
LV_STATE_DISABLED |
禁用状态 | 对象被禁用时 |
LV_STATE_CHECKED |
选中状态 | 开关、复选框等被选中时 |
状态可以组合使用:
c
// 组合状态:默认 + 按下
lv_state_t state = LV_STATE_DEFAULT | LV_STATE_PRESSED;
4.4 创建和应用样式
样式创建流程:
创建样式对象 设置默认状态属性 设置其他状态属性 应用到目标对象
代码示例:创建精美的按钮样式
cpp
#include <lvgl.h>
// ... 省略初始化代码
int main(void) {
// LVGL初始化(省略)
/********************
* 1. 创建样式对象
********************/
static lv_style_t style_btn_default; // 默认状态样式
static lv_style_t style_btn_pressed; // 按下状态样式
static lv_style_t style_btn_disabled; // 禁用状态样式
// 初始化样式对象
lv_style_init(&style_btn_default);
lv_style_init(&style_btn_pressed);
lv_style_init(&style_btn_disabled);
/********************
* 2. 配置默认状态样式(蓝色渐变按钮)
********************/
lv_style_set_bg_color(&style_btn_default, lv_color_hex(0x2196F3)); // 主蓝色
lv_style_set_bg_grad_color(&style_btn_default, lv_color_hex(0x1976D2)); // 渐变深蓝色
lv_style_set_bg_grad_dir(&style_btn_default, LV_GRAD_DIR_VER); // 垂直渐变
lv_style_set_radius(&style_btn_default, 12); // 圆角半径
lv_style_set_border_width(&style_btn_default, 0); // 无边框
lv_style_set_shadow_width(&style_btn_default, 8); // 阴影大小
lv_style_set_shadow_color(&style_btn_default, lv_color_hex(0x1A237E)); // 阴影颜色
lv_style_set_shadow_ofs_y(&style_btn_default, 4); // 阴影Y偏移
// 文字样式
lv_style_set_text_color(&style_btn_default, lv_color_white()); // 白色文字
/********************
* 3. 配置按下状态样式(深蓝色)
********************/
lv_style_set_bg_color(&style_btn_pressed, lv_color_hex(0x1976D2)); // 深蓝色
lv_style_set_bg_grad_color(&style_btn_pressed, lv_color_hex(0x0D47A1)); // 更深的蓝色
lv_style_set_shadow_ofs_y(&style_btn_pressed, 2); // 按下时阴影变小
lv_style_set_translate_y(&style_btn_pressed, 2); // 按下时下沉效果
/********************
* 4. 配置禁用状态样式(灰色)
********************/
lv_style_set_bg_color(&style_btn_disabled, lv_color_hex(0x9E9E9E)); // 灰色
lv_style_set_bg_grad_color(&style_btn_disabled, lv_color_hex(0x757575)); // 深灰色
lv_style_set_text_color(&style_btn_disabled, lv_color_hex(0xE0E0E0)); // 浅灰色文字
/********************
* 5. 创建按钮并应用样式
********************/
lv_obj_t * btn1 = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn1, 120, 50);
lv_obj_set_pos(btn1, 50, 50);
// 应用样式到不同状态
lv_obj_add_style(btn1, &style_btn_default, LV_STATE_DEFAULT);
lv_obj_add_style(btn1, &style_btn_pressed, LV_STATE_PRESSED);
lv_obj_add_style(btn1, &style_btn_disabled, LV_STATE_DISABLED);
// 添加按钮文字
lv_obj_t * label1 = lv_label_create(btn1);
lv_label_set_text(label1, "启用状态");
lv_obj_center(label1);
/********************
* 6. 创建禁用状态的按钮用于对比
********************/
lv_obj_t * btn2 = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn2, 120, 50);
lv_obj_set_pos(btn2, 200, 50);
// 应用相同的样式
lv_obj_add_style(btn2, &style_btn_default, LV_STATE_DEFAULT);
lv_obj_add_style(btn2, &style_btn_pressed, LV_STATE_PRESSED);
lv_obj_add_style(btn2, &style_btn_disabled, LV_STATE_DISABLED);
// 设置按钮为禁用状态
lv_obj_add_state(btn2, LV_STATE_DISABLED);
// 添加按钮文字
lv_obj_t * label2 = lv_label_create(btn2);
lv_label_set_text(label2, "禁用状态");
lv_obj_center(label2);
// 主循环(省略)
while(1) {
lv_timer_handler();
SDL_Delay(5);
}
return 0;
}
4.5 常用样式属性详解
LVGL提供了丰富的样式属性,主要分为以下几类:
背景属性
c
lv_style_set_bg_color(style, color); // 背景颜色
lv_style_set_bg_grad_color(style, color); // 渐变颜色
lv_style_set_bg_grad_dir(style, dir); // 渐变方向
lv_style_set_bg_main_stop(style, value); // 主颜色停止点
lv_style_set_bg_grad_stop(style, value); // 渐变颜色停止点
lv_style_set_bg_opa(style, opa); // 背景透明度 (0-255)
边框属性
c
lv_style_set_border_color(style, color); // 边框颜色
lv_style_set_border_width(style, width); // 边框宽度
lv_style_set_border_opa(style, opa); // 边框透明度
lv_style_set_border_side(style, side); // 边框边 (LEFT/RIGHT/TOP/BOTTOM/ALL)
轮廓属性
c
lv_style_set_outline_color(style, color); // 轮廓颜色
lv_style_set_outline_width(style, width); // 轮廓宽度
lv_style_set_outline_pad(style, value); // 轮廓填充
阴影属性
c
lv_style_set_shadow_color(style, color); // 阴影颜色
lv_style_set_shadow_width(style, width); // 阴影大小
lv_style_set_shadow_ofs_x(style, value); // 阴影X偏移
lv_style_set_shadow_ofs_y(style, value); // 阴影Y偏移
几何属性
c
lv_style_set_width(style, value); // 宽度
lv_style_set_height(style, value); // 高度
lv_style_set_x(style, value); // X坐标
lv_style_set_y(style, value); // Y坐标
lv_style_set_align(style, align); // 对齐方式
lv_style_set_transform_width(style, value); // 变换宽度
lv_style_set_transform_height(style, value); // 变换高度
文字属性
c
lv_style_set_text_color(style, color); // 文字颜色
lv_style_set_text_font(style, font); // 字体
lv_style_set_text_opa(style, opa); // 文字透明度
lv_style_set_text_letter_space(style, value); // 字母间距
lv_style_set_text_line_space(style, value); // 行间距
第5章:基础控件(一)- 标签、按钮与基础容器
5.1 标签:文字的载体
标签是LVGL中最基本的文本显示控件。
核心功能:
- 显示静态或动态文本
- 支持文本换行和滚动
- 支持文本对齐方式
- 支持长文本模式
数学表达:
标签的渲染可以看作一个文本布局函数:
R = L ( T , F , A , M ) R = L(T, F, A, M) R=L(T,F,A,M)
其中:
- R R R = 渲染结果
- T T T = 文本内容
- F F F = 字体属性
- A A A = 对齐方式
- M M M = 长文本模式
代码示例:标签的各种用法
cpp
// 创建基础标签
lv_obj_t * label1 = lv_label_create(lv_scr_act());
lv_label_set_text(label1, "这是基础标签");
lv_obj_set_pos(label1, 10, 10);
// 创建长文本标签(自动换行)
lv_obj_t * label2 = lv_label_create(lv_scr_act());
lv_obj_set_size(label2, 200, 100); // 必须设置大小才能换行
lv_obj_set_pos(label2, 10, 40);
lv_label_set_text(label2, "这是一个很长的文本,它会在标签边界处自动换行,确保所有内容都能正确显示。");
lv_label_set_long_mode(label2, LV_LABEL_LONG_WRAP); // 换行模式
// 创建滚动文本标签
lv_obj_t * label3 = lv_label_create(lv_scr_act());
lv_obj_set_size(label3, 150, 25);
lv_obj_set_pos(label3, 10, 150);
lv_label_set_text(label3, "这是一个会水平滚动的文本,当文本过长时...");
lv_label_set_long_mode(label3, LV_LABEL_LONG_SCROLL); // 滚动模式
// 创建居中对齐标签
lv_obj_t * label4 = lv_label_create(lv_scr_act());
lv_obj_set_size(label4, 200, 30);
lv_obj_set_pos(label4, 10, 190);
lv_label_set_text(label4, "居中对齐的文本");
lv_obj_set_style_text_align(label4, LV_TEXT_ALIGN_CENTER, 0);
// 动态更新文本
static int counter = 0;
lv_obj_t * dynamic_label = lv_label_create(lv_scr_act());
lv_obj_set_pos(dynamic_label, 10, 230);
// 在定时器中更新文本
lv_timer_t * timer = lv_timer_create([](lv_timer_t * timer) {
static int count = 0;
lv_label_set_text_fmt((lv_obj_t *)timer->user_data, "计数器: %d", count++);
}, 1000, dynamic_label);
5.2 按钮:交互的基础
按钮是最常用的交互控件,它本身是一个容器,通常内部包含标签。
按钮状态机:
按下 释放 禁用 启用 切换(如开关) 取消切换 DEFAULT PRESSED DISABLED CHECKED
代码示例:创建功能性按钮
cpp
// 创建普通按钮
lv_obj_t * btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 40);
lv_obj_set_pos(btn, 250, 50);
// 添加按钮文字
lv_obj_t * btn_label = lv_label_create(btn);
lv_label_set_text(btn_label, "点击我");
lv_obj_center(btn_label);
// 创建开关式按钮
lv_obj_t * toggle_btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(toggle_btn, 100, 40);
lv_obj_set_pos(toggle_btn, 250, 100);
lv_obj_add_flag(toggle_btn, LV_OBJ_FLAG_CHECKABLE); // 使按钮可切换
lv_obj_t * toggle_label = lv_label_create(toggle_btn);
lv_label_set_text(toggle_label, "开关");
lv_obj_center(toggle_label);
5.3 基础容器:布局的基石
容器本身没有特定的外观,主要用于组织和布局子对象。
容器的核心作用:
- 分组相关控件
- 简化布局管理
- 控制子对象的可见性和位置
代码示例:使用容器组织界面
cpp
// 创建主容器
lv_obj_t * container = lv_obj_create(lv_scr_act());
lv_obj_set_size(container, 280, 180);
lv_obj_set_pos(container, 10, 270);
lv_obj_set_flex_flow(container, LV_FLEX_FLOW_COLUMN); // 垂直排列
lv_obj_set_style_pad_all(container, 10, 0); // 内边距
// 在容器内创建标题标签
lv_obj_t * title = lv_label_create(container);
lv_label_set_text(title, "设置面板");
lv_obj_set_style_text_font(title, &lv_font_montserrat_16, 0);
// 创建水平排列的按钮组
lv_obj_t * btn_container = lv_obj_create(container);
lv_obj_set_size(btn_container, lv_pct(100), 50);
lv_obj_set_flex_flow(btn_container, LV_FLEX_FLOW_ROW); // 水平排列
lv_obj_set_style_bg_opa(btn_container, LV_OPA_0, 0); // 透明背景
lv_obj_set_style_border_width(btn_container, 0, 0); // 无边框
// 在按钮容器中添加多个按钮
for(int i = 0; i < 3; i++) {
lv_obj_t * btn = lv_btn_create(btn_container);
lv_obj_set_flex_grow(btn, 1); // 等分宽度
lv_obj_t * label = lv_label_create(btn);
lv_label_set_text_fmt(label, "选项 %d", i + 1);
lv_obj_center(label);
}
第6章:基础控件(二)- 滑块、开关、进度条
6.1 滑块:精确的数值输入
滑块允许用户通过拖动来选择特定范围内的数值。
滑块的值映射:
滑块将一个物理位置映射到一个数值范围内:
v a l u e = m i n + p o s i t i o n m a x _ p o s i t i o n × ( m a x − m i n ) value = min + \frac{position}{max\_position} \times (max - min) value=min+max_positionposition×(max−min)
其中:
- v a l u e value value = 当前值
- m i n min min, m a x max max = 值范围
- p o s i t i o n position position = 滑块当前位置
- m a x _ p o s i t i o n max\_position max_position = 滑块最大可移动范围
代码示例:创建多功能滑块
cpp
// 创建水平滑块
lv_obj_t * slider1 = lv_slider_create(lv_scr_act());
lv_obj_set_size(slider1, 200, 20);
lv_obj_set_pos(slider1, 400, 50);
lv_slider_set_range(slider1, 0, 100); // 设置范围 0-100
lv_slider_set_value(slider1, 30, LV_ANIM_OFF); // 设置初始值
// 创建垂直滑块
lv_obj_t * slider2 = lv_slider_create(lv_scr_act());
lv_obj_set_size(slider2, 20, 150);
lv_obj_set_pos(slider2, 450, 80);
lv_slider_set_range(slider2, 0, 100);
lv_slider_set_value(slider2, 70, LV_ANIM_OFF);
// 显示滑块值的标签
lv_obj_t * slider_label = lv_label_create(lv_scr_act());
lv_obj_set_pos(slider_label, 400, 80);
// 滑块事件处理
lv_obj_add_event_cb(slider1, [](lv_event_t * e) {
lv_obj_t * slider = lv_event_get_target(e);
int32_t value = lv_slider_get_value(slider);
// 更新标签显示
lv_label_set_text_fmt((lv_obj_t *)lv_event_get_user_data(e),
"值: %d%%", value);
}, LV_EVENT_VALUE_CHANGED, slider_label);
6.2 开关:二进制状态选择
开关用于表示开/关、是/否等二进制状态。
开关的布尔逻辑:
s t a t e = { true if checked false if unchecked state = \begin{cases} \text{true} & \text{if checked} \\ \text{false} & \text{if unchecked} \end{cases} state={truefalseif checkedif unchecked
代码示例:创建状态开关
cpp
// 创建开关
lv_obj_t * sw = lv_switch_create(lv_scr_act());
lv_obj_set_pos(sw, 400, 150);
// 创建开关状态标签
lv_obj_t * sw_label = lv_label_create(lv_scr_act());
lv_obj_set_pos(sw_label, 480, 150);
lv_label_set_text(sw_label, "关");
// 开关事件处理
lv_obj_add_event_cb(sw, [](lv_event_t * e) {
lv_obj_t * sw = lv_event_get_target(e);
bool state = lv_obj_has_state(sw, LV_STATE_CHECKED);
lv_label_set_text((lv_obj_t *)lv_event_get_user_data(e),
state ? "开" : "关");
}, LV_EVENT_VALUE_CHANGED, sw_label);
6.3 进度条:操作反馈与状态显示
进度条用于显示操作的进度或系统的状态。
进度计算:
p r o g r e s s = c u r r e n t − m i n m a x − m i n × 100 % progress = \frac{current - min}{max - min} \times 100\% progress=max−mincurrent−min×100%
代码示例:创建动态进度条
cpp
// 创建进度条
lv_obj_t * progress_bar = lv_bar_create(lv_scr_act());
lv_obj_set_size(progress_bar, 200, 20);
lv_obj_set_pos(progress_bar, 400, 200);
lv_bar_set_range(progress_bar, 0, 100); // 设置范围
lv_bar_set_value(progress_bar, 0, LV_ANIM_OFF);
// 进度标签
lv_obj_t * progress_label = lv_label_create(lv_scr_act());
lv_obj_set_pos(progress_label, 400, 230);
lv_label_set_text(progress_label, "0%");
// 模拟进度更新
static int progress = 0;
lv_timer_t * progress_timer = lv_timer_create([](lv_timer_t * timer) {
if(progress >= 100) {
lv_timer_del(timer);
return;
}
progress += 2;
lv_bar_set_value((lv_obj_t *)timer->user_data, progress, LV_ANIM_ON);
// 更新标签
lv_label_set_text_fmt(progress_label, "%d%%", progress);
}, 100, progress_bar);
6.4 综合实战:创建简易调光器界面
现在让我们综合运用所学知识,创建一个完整的调光器控制面板:
cpp
void create_dimmer_interface() {
// 创建主容器
lv_obj_t * container = lv_obj_create(lv_scr_act());
lv_obj_set_size(container, 300, 200);
lv_obj_align(container, LV_ALIGN_TOP_RIGHT, -20, 20);
lv_obj_set_style_bg_color(container, lv_color_hex(0x2C3E50), 0);
lv_obj_set_style_radius(container, 15, 0);
// 标题
lv_obj_t * title = lv_label_create(container);
lv_label_set_text(title, "LED调光器");
lv_obj_set_style_text_color(title, lv_color_white(), 0);
lv_obj_set_style_text_font(title, &lv_font_montserrat_18, 0);
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 15);
// 亮度滑块
lv_obj_t * brightness_slider = lv_slider_create(container);
lv_obj_set_size(brightness_slider, 200, 20);
lv_obj_align(brightness_slider, LV_ALIGN_TOP_MID, 0, 60);
lv_slider_set_range(brightness_slider, 0, 100);
lv_slider_set_value(brightness_slider, 75, LV_ANIM_OFF);
// 亮度标签
lv_obj_t * brightness_label = lv_label_create(container);
lv_obj_set_style_text_color(brightness_label, lv_color_white(), 0);
lv_obj_align_to(brightness_label, brightness_slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
// 开关控制
lv_obj_t * power_switch = lv_switch_create(container);
lv_obj_align(power_switch, LV_ALIGN_TOP_MID, 0, 120);
lv_obj_t * power_label = lv_label_create(container);
lv_label_set_text(power_label, "电源");
lv_obj_set_style_text_color(power_label, lv_color_white(), 0);
lv_obj_align_to(power_label, power_switch, LV_ALIGN_OUT_LEFT_MID, -10, 0);
// 事件处理:更新亮度显示
lv_obj_add_event_cb(brightness_slider, [](lv_event_t * e) {
lv_obj_t * slider = lv_event_get_target(e);
int32_t value = lv_slider_get_value(slider);
lv_label_set_text_fmt((lv_obj_t *)lv_event_get_user_data(e),
"亮度: %d%%", value);
}, LV_EVENT_VALUE_CHANGED, brightness_label);
// 初始化亮度显示
lv_event_send(brightness_slider, LV_EVENT_VALUE_CHANGED, NULL);
// 事件处理:开关状态
lv_obj_add_event_cb(power_switch, [](lv_event_t * e) {
lv_obj_t * sw = lv_event_get_target(e);
bool enabled = lv_obj_has_state(sw, LV_STATE_CHECKED);
// 这里可以添加实际的LED控制逻辑
printf("LED %s\n", enabled ? "开启" : "关闭");
}, LV_EVENT_VALUE_CHANGED, NULL);
}
在main函数中调用:
cpp
int main(void) {
// ... 初始化代码
create_dimmer_interface();
// ... 主循环
}
本章总结与挑战
恭喜!你已经掌握了LVGL的核心构建块。你现在能够:
- 理解LVGL的面向对象模型和对象树概念
- 创建和配置丰富的样式系统,实现精美的UI效果
- 熟练使用基础控件:标签、按钮、容器、滑块、开关、进度条
- 组合多个控件创建功能完整的用户界面
小挑战(巩固练习):
- 样式进阶:为调光器界面添加按下状态的样式效果,让按钮和滑块在交互时有视觉反馈。
- 布局优化:使用容器和Flex布局重新组织调光器界面,使其在不同屏幕尺寸下都能良好显示。
- 功能扩展:在调光器界面中添加颜色选择功能,使用多个滑块分别控制RGB值。
- 状态联动:实现当电源开关关闭时,自动禁用亮度滑块并将其值设置为0。
在下一篇文章中,我们将深入探讨事件系统 和高级布局技术(Flex和Grid),让你能够创建更加动态和响应式的用户界面。
研究学习不易,点赞易。
工作生活不易,收藏易,点收藏不迷茫 :)