当前位置: 首页 > ops >正文

[LVGL] 部件lv_obj | 样式lv_style | LV_PART_ | LV_STATE_

示例代码: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父指针创建屏幕:

#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

// ...(接续前段代码)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)是专用于文本显示的部件。将其父级设为按钮即可实现文本嵌入:

// ...(接续前段代码)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(部件句柄)会递归删除所有子级并释放内存
// 部件删除示例
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()时,实质是修改flagsstate变量:

// 简化版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_style)

在第三章:部件(lv_obj)中,我们学习了如何将按钮和文本标签等基础元素放置到屏幕。

虽然实现了简单的"Hello LVGL!"按钮,但它的外观略显单调——灰色矩形搭配黑色文本。

**样式(lv_style)**正是为此而生!想象我们拥有素色乐高积木(部件),现在要为它们添加涂装、纹样、圆角甚至发光特效。

LVGL的样式系统正是这样的视觉装饰系统,通过预定义外观模板实现界面元素的美化。

什么是样式?(lv_style_t

LVGL样式本质是lv_style_t类型变量,可存储多种视觉属性集合,类似于网页设计的CSS类。其核心属性包括:

  • 色彩属性:背景色、边框色、文本色
  • 尺寸定位:内边距(部件内部留白)、外边距(外部留白)、边框宽度
  • 形态特征:圆角半径(实现圆角矩形)
  • 文本特性:字体、字间距、行距、对齐方式
  • 视觉效果:阴影、透明度、图像重着色

创建并应用首个样式

让我们优化第三章按钮的视觉效果,实现蓝色背景与圆角设计:

1. 初始化样式

首先声明静态或全局的lv_style_t变量并进行初始化:

#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. 配置样式属性

设置蓝色背景与圆角属性:

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. 应用样式至部件

将样式绑定至第三章创建的按钮:

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多元素部件(如表格单元格)

示例:为滑块旋钮设置独立样式:

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鼠标悬停状态

示例:按钮按压状态变色:

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支持多重样式叠加,遵循后添加样式优先原则:

// 基础按钮样式(灰色背景)
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圆角,体现后添加样式的属性覆盖特性。

属性继承机制

部分文本相关属性具备继承性,子部件未定义时继承父级设置:

// 全局字体样式(屏幕级继承)
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); // 子部件继承字体设置

本地样式(快速定制)

支持直接为特定部件设置独立属性,优先级最高:

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采用延迟计算机制优化渲染性能:

内部数据结构说明:

struct _lv_obj_t {lv_obj_style_t * styles; // 样式指针数组uint16_t style_cnt;       // 样式数量// 其他属性...
};

总结

本章全面掌握LVGL样式系统,核心要点包括:

  • 样式初始化与属性配置流程
  • 部件组成单元与交互状态的精确控制
  • 层叠样式优先级规则与继承机制
  • 本地样式的快速定制方法
  • 样式系统的底层存储与计算逻辑

通过灵活运用样式系统,开发者可实现专业级视觉设计效果,为后续布局系统学习奠定基础。

在这里插入图片描述
图形化可以使用:
在这里插入图片描述

下一章:布局系统(lv_flex, lv_grid)

http://www.xdnf.cn/news/17104.html

相关文章:

  • Cartographer安装测试与模块开发(四)--Cartographer纯定位思路
  • Linux基本指令:掌握系统操作的钥匙
  • 浅谈RNN被Transformer 取代的必然性
  • 面试题:基础的sql命令
  • 在LLM小型化趋势下,AI Infra需要做出哪些相应调整?
  • 【完整源码+数据集+部署教程】爬行动物异常检测系统源码和数据集:改进yolo11-GhostDynamicConv
  • JavaScript 中 var、let 和 const 的区别与使用场景
  • TCP的三次握手和四次挥手实现过程。以及为什么需要三次握手?四次挥手?
  • [GESP202309 四级] 2023年9月GESP C++四级上机题题解,附带讲解视频!
  • Python爬虫08_Requests聚焦批量爬取图片
  • layernorm backward CUDA优化分析
  • linux nfs+autofs
  • mq_unlink系统调用及示例
  • Java开发时出现的问题---并发与资源管理深层问题
  • 在具身智能火热加持下,看 2025 年机器人学术年会中的热点主题。PNP机器人展示力控、灵巧手捕捉等案例。
  • Android Studio下载及安装配置
  • 计算机视觉的四项基本任务辨析
  • Android audio之 AudioDeviceInventory
  • 飞算JavaAI需求转SpringBoot项目:从零到一的沉浸式开发之旅
  • 人工智能之数学基础:利用全概率公式如何将复杂事件转为简单事件
  • 学习游戏制作记录(将各种属性应用于战斗以及实体的死亡)8.5
  • DM8日常运维命令总结(四)
  • Go语言 string
  • 数据结构——双向链表
  • Linux 调度器函数sched_*系统调用及示例
  • 【音视频】WebRTC 一对一通话-信令服
  • Go语言实战案例:使用context控制协程取消
  • 算法训练之哈希表
  • Java后端高频面试题
  • React在使用create-react-app创建项目慢的解决办法