示例代码:https://github.com/lvy010/Cpp-Lib-test/tree/main/LVGL
第三章:部件(lv_obj)
欢迎回来!在第二章:显示屏(lv_display)中,我们学习了如何配置LVGL以理解物理屏幕并进行绘制。
我们为图形创作搭建了"画布"。但若没有画笔或特定形状,画布又有何用?
**部件(lv_obj
)**正是为此而生!部件是LVGL用户界面的基本构建单元,可类比为乐高积木。我们并非直接在屏幕上绘制原始像素,而是使用预定义的形状元素,如按钮、文本标签、滑块或简单矩形区域。每个"积木"都有其特定用途、外观和行为。
本章目标是通过构建包含文本的简单按钮界面,理解这些基础构建单元。
什么是部件?(lv_obj_t
基类)
本质上,LVGL屏幕上的所有元素(按钮、标签、滑块、图像等)都基于lv_obj_t
类型。我们可以将lv_obj_t
视为"基础部件",所有其他专用部件均由其派生而来。
所有部件均继承lv_obj_t
的通用能力:
- 位置:在屏幕上的坐标
- 尺寸:长宽像素值
- 父子关系:在容器内的组织结构
- 样式:视觉呈现(颜色、边框、字体等,详见后续章节)
- 事件:对用户输入的响应(如点击)
创建任意LVGL部件时,均会获得lv_obj_t
类型的指针,该指针即部件的控制句柄。
创建首个部件:屏幕、按钮与标签
我们从构建带文本的简单按钮开始。
1. 屏幕:顶级部件
添加界面元素前,需先创建"屏幕"。在LVGL中,屏幕是特殊的无父部件lv_obj_t
,自动占据整个显示屏(lv_display)空间。
通过向lv_obj_create()
传入NULL
父指针创建屏幕:
c
#include "lvgl.h" // 必须包含LVGL主头文件
void create_my_ui()
{
// 创建屏幕对象。由于是首个无父对象(NULL),自动成为活动屏幕
lv_obj_t * screen_main = lv_obj_create(NULL);
// 屏幕自动覆盖全屏,无需设置尺寸/位置
// 显式加载此屏幕(若为首个屏幕通常自动加载)
lv_screen_load(screen_main);
// 现在可向屏幕添加其他部件!
}
lv_obj_create(NULL)
:创建基础矩形部件,因父指针为NULL
转为屏幕lv_obj_t * screen_main
:保存新屏幕的句柄,用于添加子部件lv_screen_load(screen_main)
:确保当前显示该屏幕(首屏可省略)
2. 向屏幕添加按钮
按钮(lv_button
)是继承自lv_obj_t
的专用部件,默认支持点击交互。
创建部件时需指定parent
参数,此处父级为screen_main
:
c
// ...(接续前段代码)
void create_my_ui()
{
lv_obj_t * screen_main = lv_obj_create(NULL);
lv_screen_load(screen_main);
// 在'screen_main'上创建按钮
lv_obj_t * button1 = lv_button_create(screen_main);
// 设置尺寸(宽度,高度,单位像素)
lv_obj_set_size(button1, 120, 50);
// 设置相对父级(screen_main)的坐标
// 使用居中对齐函数简化定位
lv_obj_set_align(button1, LV_ALIGN_CENTER);
}
lv_button_create(screen_main)
:创建按钮部件,父级为screen_main
lv_obj_set_size()
:通用尺寸设置函数,适用于所有部件LV_ALIGN_CENTER
:便捷居中函数,替代手动计算坐标
3. 为按钮添加标签(文本)
标签(lv_label
)是专用于文本显示的部件。将其父级设为按钮即可实现文本嵌入:
c
// ...(接续前段代码)
void create_my_ui()
{
lv_obj_t * screen_main = lv_obj_create(NULL);
lv_screen_load(screen_main);
lv_obj_t * button1 = lv_button_create(screen_main);
lv_obj_set_size(button1, 120, 50);
lv_obj_set_align(button1, LV_ALIGN_CENTER);
// 在'button1'上创建标签
lv_obj_t * label1 = lv_label_create(button1);
// 设置标签文本
lv_label_set_text(label1, "Hello LVGL!");
// 居中标签文本
lv_obj_set_align(label1, LV_ALIGN_CENTER);
}
lv_label_create(button1)
:创建标签,父级为按钮lv_label_set_text()
:标签专用文本设置函数- 再次使用
LV_ALIGN_CENTER
实现文本居中
完成上述配置后,结合第二章的显示设置并定期调用lv_timer_handler()
,即可在屏幕中央看到带文本的按钮
理解父子关系
父子层级是LVGL的核心组织逻辑,类似于树状结构或嵌套容器:
- 每个部件(除屏幕)有唯一父级
- 父级可含多个子级
- 相对定位:子级坐标基于父级左上角,父级移动时子级自动跟随
- 可见性裁剪:子级超出父级区域部分默认不可见,类似视窗效果
这种层级结构简化了复杂界面的管理:
创建与删除部件
部件支持运行时动态创建/删除,这对内存受限的嵌入式系统尤为重要:
- 创建 :使用
lv_obj_create(parent)
或lv_<部件类型>_create(parent)
- 删除 :
lv_obj_delete(部件句柄)
会递归删除所有子级并释放内存
c
// 部件删除示例
void delete_my_button(lv_obj_t * button_to_delete)
{
// 删除按钮及其子级(标签)
lv_obj_delete(button_to_delete);
}
// 延迟删除(毫秒)
lv_obj_delete_delayed(button1, 1000);
// 异步删除(下次定时器周期)
lv_obj_delete_async(button1);
部件底层
调用lv_obj_create()
或lv_<部件>_create()
时,LVGL执行以下流程:

每个lv_obj_t
结构体包含关键信息:
lv_area_t coords
:部件坐标与尺寸(左上/右下坐标)lv_obj_t * parent
:父级指针lv_obj_flag_t flags
:状态标志位(如可点击性、隐藏状态)lv_state_t state
:可视化状态(如按下、禁用)const lv_obj_class_t * class_p
:部件类型指针(如基础对象类、按钮类)
调用lv_obj_add_flag()
或lv_obj_add_state()
时,实质是修改flags
和state
变量:
c
// 简化版lv_obj_add_flag实现
void lv_obj_add_flag(lv_obj_t * obj, lv_obj_flag_t f) {
obj->flags |= f; // 位运算添加标志
lv_obj_invalidate(obj); // 触发重绘
}
// 应用示例:启用按钮点击
lv_obj_add_flag(button1, LV_OBJ_FLAG_CLICKABLE);
LVGL核心文件lv_obj.c
处理基础部件的创建、管理与绘制逻辑。专用部件(如按钮)在基础对象上扩展特性与默认样式。这种分层设计使开发者无需关注底层绘制细节,专注实现业务逻辑。
总结
我们已掌握LVGL部件的核心概念:
lv_obj_t
是所有UI元素的基类- 部件通过父子层级组织,屏幕作为顶级容器
- 支持动态创建/删除以优化内存使用
- 通用属性通过
lv_obj
函数管理,专用功能由部件类型函数实现
理解部件机制是构建可视化界面的关键。下一步我们将学习如何美化部件外观!
第四章:样式(lv_style)
在第三章:部件(lv_obj)中,我们学习了如何将按钮和文本标签等基础元素放置到屏幕。
虽然实现了简单的"Hello LVGL!"按钮,但它的外观略显单调------灰色矩形搭配黑色文本。
**样式(lv_style
)**正是为此而生!想象我们拥有素色乐高积木(部件),现在要为它们添加涂装、纹样、圆角甚至发光特效。
LVGL的样式系统正是这样的视觉装饰系统,通过预定义
外观模板实现界面元素的美化。
什么是样式?(lv_style_t
)
LVGL样式本质是lv_style_t
类型变量,可存储多种视觉属性集合,类似于网页设计的CSS类
。其核心属性包括:
- 色彩属性:背景色、边框色、文本色
- 尺寸定位:内边距(部件内部留白)、外边距(外部留白)、边框宽度
- 形态特征:圆角半径(实现圆角矩形)
- 文本特性:字体、字间距、行距、对齐方式
- 视觉效果:阴影、透明度、图像重着色
创建并应用首个样式
让我们优化第三章按钮的视觉效果,实现蓝色背景与圆角设计:
1. 初始化样式
首先声明静态或全局的lv_style_t
变量并进行初始化:
c
#include "lvgl.h"
// 声明静态样式变量
static lv_style_t my_button_style;
void setup_my_styles() {
// 样式初始化(关键步骤)
lv_style_init(&my_button_style);
// 后续将添加属性配置
}
static lv_style_t my_button_style
:静态声明确保样式变量持久化lv_style_init()
:样式初始化标准操作,清空原有配置
2. 配置样式属性
设置蓝色背景与圆角属性:
c
void setup_my_styles() {
lv_style_init(&my_button_style);
// 设置海蓝色背景
lv_style_set_bg_color(&my_button_style, lv_color_hex(0x007BFF));
lv_style_set_bg_opa(&my_button_style, LV_OPA_COVER); // 完全覆盖不透明
// 设置10像素圆角半径
lv_style_set_radius(&my_button_style, 10);
}
lv_color_hex()
:十六进制颜色码转LVGL颜色结构LV_OPA_COVER
:全不透明宏定义(LV_OPA_TRANSP
为全透明)
3. 应用样式至部件
将样式绑定至第三章创建的按钮:
c
void create_my_ui() {
lv_obj_t * screen_main = lv_obj_create(NULL);
lv_screen_load(screen_main);
lv_obj_t * button1 = lv_button_create(screen_main);
lv_obj_set_size(button1, 120, 50);
lv_obj_set_align(button1, LV_ALIGN_CENTER);
// 应用新样式(参数0表示LV_PART_MAIN|LV_STATE_DEFAULT)
lv_obj_add_style(button1, &my_button_style, 0);
lv_obj_t * label1 = lv_label_create(button1);
lv_label_set_text(label1, "Hello LVGL!");
lv_obj_set_align(label1, LV_ALIGN_CENTER);
}
部件组成单元(LV_PART_
)
复杂部件(如滑块)包含多个视觉组件,LVGL允许对各部分独立设置样式:
组成单元宏定义 | 描述 |
---|---|
LV_PART_MAIN |
主体背景区域 |
LV_PART_SCROLLBAR |
滚动条组件 |
LV_PART_INDICATOR |
进度指示器(如滑块进度条) |
LV_PART_KNOB |
可拖动旋钮 |
LV_PART_ITEMS |
多元素部件(如表格单元格) |
示例:为滑块旋钮设置独立样式:
c
lv_obj_t * my_slider = lv_slider_create(screen_main);
static lv_style_t knob_style;
lv_style_init(&knob_style);
lv_style_set_bg_color(&knob_style, lv_color_hex(0xFF0000)); // 红色旋钮
lv_style_set_radius(&knob_style, LV_RADIUS_CIRCLE); // 正圆形
// 仅应用于旋钮部分
lv_obj_add_style(my_slider, &knob_style, LV_PART_KNOB);
状态响应(LV_STATE_
)
GUI元素在不同交互状态下呈现差异化的视觉效果:
状态宏定义 | 触发条件 |
---|---|
LV_STATE_DEFAULT |
默认未激活状态 |
LV_STATE_PRESSED |
按压状态 |
LV_STATE_FOCUSED |
焦点状态(键盘/触控选择) |
LV_STATE_CHECKED |
切换激活状态(如开关开启) |
LV_STATE_DISABLED |
禁用不可用状态 |
LV_STATE_HOVERED |
鼠标悬停状态 |
示例:按钮按压状态变色:
c
static lv_style_t my_button_pressed_style;
void setup_my_styles() {
// 默认状态样式配置...
// 按压状态深蓝色背景
lv_style_init(&my_button_pressed_style);
lv_style_set_bg_color(&my_button_pressed_style, lv_color_hex(0x0056b3));
}
void create_my_ui() {
// 应用默认状态样式
lv_obj_add_style(button1, &my_button_style, 0);
// 应用按压状态样式
lv_obj_add_style(button1, &my_button_pressed_style, LV_STATE_PRESSED);
}
层叠样式(优先级覆盖)
LVGL支持多重样式叠加,遵循后添加样式优先原则:
c
// 基础按钮样式(灰色背景)
static lv_style_t base_button_style;
lv_style_set_bg_color(&base_button_style, lv_color_grey());
lv_style_set_radius(&base_button_style, 5);
// 变体样式(仅修改背景色)
static lv_style_t red_button_variant_style;
lv_style_set_bg_color(&red_button_variant_style, lv_color_red());
lv_obj_t * button = lv_button_create(screen);
lv_obj_add_style(button, &base_button_style, 0); // 基础样式
lv_obj_add_style(button, &red_button_variant_style, 0);// 红色变体样式(覆盖背景色)
最终效果:红色背景+5px圆角,体现后添加样式的属性覆盖特性。
属性继承机制
部分文本相关属性具备继承性,子部件未定义时继承父级设置:
c
// 全局字体样式(屏幕级继承)
static lv_style_t global_font_style;
lv_style_set_text_font(&global_font_style, &lv_font_montserrat_28);
lv_style_set_text_color(&global_font_style, lv_color_black());
lv_obj_t * screen_main = lv_obj_create(NULL);
lv_obj_add_style(screen_main, &global_font_style, 0); // 子部件继承字体设置
本地样式(快速定制)
支持直接为特定部件设置独立属性,优先级最高:
c
lv_obj_t * button = lv_button_create(screen_main);
lv_obj_set_style_bg_color(button, lv_color_make(255, 128, 0), 0); // 橙色本地样式
lv_obj_set_style_radius(button, 20, 0); // 独立圆角设置
样式系统工作原理
LVGL采用延迟计算机制优化渲染性能:
内部数据结构说明:
c
struct _lv_obj_t {
lv_obj_style_t * styles; // 样式指针数组
uint16_t style_cnt; // 样式数量
// 其他属性...
};
总结
本章全面掌握LVGL样式系统,核心要点包括:
样式初始化
与属性配置流程部件
组成单元与交互状态的精确控制层叠样式优先级
规则与继承机制- 本地样式的快速定制方法
- 样式系统的
底层存储
与计算逻辑
通过灵活运用样式系统,开发者可实现专业级视觉设计效果,为后续布局系统学习奠定基础。

图形化可以使用: