LVGL列表与下拉菜单:实战项目应用解析

LVGL实战:用列表与下拉菜单打造高效嵌入式HMI

你有没有遇到过这样的场景?在一台工业控制器上,想改个通信波特率,结果要点五六次“+”按钮才能从9600跳到115200——不仅效率低,用户还容易按错。又或者,在智能家居面板里,主菜单靠一堆并列按钮堆出来,滑动卡顿、布局混乱,看起来像上世纪的界面。

这些问题的本质,是缺乏对现代GUI组件的系统性理解与工程化应用。而解决它们的关键,就藏在LVGL 的两个看似普通却极为强大的控件中:列表(List)和下拉菜单(Dropdown)

今天,我们不讲理论套话,也不罗列API文档。我们要做的,是从一个真实项目出发,手把手带你把这两个组件用活、用深、用出工程价值。


为什么选 List 和 Dropdown?

先说结论:

在资源受限的嵌入式系统中,List 是导航中枢,Dropdown 是配置核心

它们不是“能用就行”的备选项,而是构建专业级HMI的基础架构单元

举个例子。你在开发一款基于STM32H7 + 480×272 TFT屏的医疗设备操作终端。需求很明确:

  • 主界面要有功能入口(设置、校准、数据导出);
  • 进入设置后要能切换语言、选择串口参数、调节背光亮度;
  • 所有操作必须支持触摸和编码器输入;
  • 内存紧张,总可用RAM仅128KB,GUI占用不能超过30KB。

如果你还在用lv_btn手动排布按钮、自己写弹窗逻辑……那恭喜你,代码会迅速膨胀,维护成本飙升,用户体验也难以保证一致性。

但如果你熟练掌握List 和 Dropdown,你会发现:这些需求几乎已经被LVGL“预判”了。


列表(List):不只是按钮集合

很多人以为lv_list_t就是一组带图标的按钮垂直排列。这没错,但远远不够。

它真正的价值,在于“结构化导航”

想象一下Android或iOS的应用菜单——层级清晰、滚动流畅、点击反馈自然。LVGL的List就是让你在MCU上复刻这种体验。

核心机制拆解

List 并不是一个简单的容器。它的底层其实是一个智能按钮管理器 + 滚动引擎 + 焦点调度器的组合体。

当你调用:

lv_obj_t *btn = lv_list_add_btn(list, LV_SYMBOL_WIFI, "Wi-Fi Network");

LVGL 做了什么?

  1. 创建一个lv_btn
  2. 自动在按钮内部创建lv_label显示文本;
  3. 如果提供了符号(如LV_SYMBOL_WIFI),则创建lv_img插入左侧;
  4. 绑定默认点击行为(高亮 + 触发事件);
  5. 将其添加到垂直布局中,并更新滚动范围。

整个过程无需手动计算位置、对齐方式或事件绑定——这是封装带来的生产力跃迁

工程实践中的关键点
✅ 动态加载 vs 静态构造

如果列表项固定且数量少(<5项),直接初始化时全部添加即可。

但如果面对的是“历史记录”、“设备日志”这类可能上百条的内容,就必须考虑内存问题。

建议策略
- 启用懒加载:只显示可视区域附近的条目;
- 使用lv_obj_clean(list)清空后再重填;
- 或者更进一步,结合lv_fragment模块实现分页加载(需启用LV_USE_FRAGMENT)。

✅ 支持非触摸设备

很多工业设备仍使用编码器+确认键。这时候,List 必须配合焦点系统工作。

lv_group_t *g = lv_group_create(); lv_group_add_obj(g, list); // 将list加入输入组 lv_indev_set_group(knob_indev, g); // 编码器关联该组

这样用户就能通过旋转编码器上下移动焦点,按压确认进入子页面——完全模拟物理按键交互。

✅ 性能优化技巧
  • 关闭不必要的滚动条:lv_obj_set_scrollbar_mode(list, LV_SCROLLBAR_MODE_OFF)
  • 设置合适的内边距避免重绘扩散:lv_obj_set_style_pad_all(list, 8, 0);
  • 对长文本启用省略显示:lv_obj_set_style_text_overflow(label, LV_TEXT_OVERFLOW_CLIP, 0);

下拉菜单(Dropdown):小空间里的大智慧

如果说 List 解决的是“怎么组织功能”,那么 Dropdown 解决的就是“如何高效选择参数”。

它的本质,是一个“按需展开的选择器”

初始状态它只占一行高度,点击后才动态生成浮层列出所有选项。这种设计在仪表盘、参数配置页中极具优势。

内部是怎么运作的?

Dropdown 表面看是个输入框,实际上包含两部分:

  1. 主控件:显示当前值的文本区域;
  2. 弹出层(Popup):点击时创建的临时浮窗,本质是一个精简版列表。

所有选项以\n分隔字符串形式存储在内部缓冲区。例如:

"中文\nEnglish\n日本語"

当用户点击时,LVGL 会动态创建一个居中浮层,每一行作为一个可点击项。选择后自动关闭并更新主文本。

为什么比手动画弹窗更好?
手动实现LVGL Dropdown
需管理窗口生命周期自动创建/销毁
需处理遮挡与层级内建z-index机制
易出现内存泄漏固定缓冲区大小可控
交互不一致统一动画与焦点行为

更重要的是:它原生支持键盘导航、索引访问、动态更新

实战代码详解
// 创建下拉菜单 lv_obj_t *dd = lv_dropdown_create(lv_scr_act()); lv_obj_set_width(dd, 120); lv_obj_align(dd, LV_ALIGN_TOP_RIGHT, -10, 10); // 设置选项 lv_dropdown_set_options(dd, "1s\n5s\n10s\n30s"); // 默认选中第3项(10秒) lv_dropdown_set_selected(dd, 2); // 添加事件监听 lv_obj_add_event_cb(dd, on_interval_changed, LV_EVENT_VALUE_CHANGED, NULL);

回调函数中可以这样读取:

void on_interval_changed(lv_event_t *e) { lv_obj_t *dd = lv_event_get_target(e); uint8_t idx = lv_dropdown_get_selected(dd); uint32_t interval_ms; switch(idx) { case 0: interval_ms = 1000; break; case 1: interval_ms = 5000; break; case 2: interval_ms = 10000; break; case 3: interval_ms = 30000; break; } // 更新定时器或其他模块 update_sampling_interval(interval_ms); }
高阶技巧
🔍 启用首字母搜索

对于长列表(如国家选择),开启动态标志后,用户输入“A”即可快速定位到“America”:

lv_dropdown_add_flag(dd, LV_DROPDOWN_FLAG_DYNAMIC);

注意:此功能依赖输入设备支持字符输入(如 keypad),并非所有硬件都适用。

🌍 多语言适配方案

不要硬编码字符串!推荐结合lv_i18n模块:

extern const char *lang_options_en[]; extern const char *lang_options_zh[]; void update_language_dd(lv_obj_t *dd, int lang_id) { const char **opts = (lang_id == LANG_ZH) ? lang_options_zh : lang_options_en; char buf[256] = {0}; for(int i = 0; opts[i]; i++) { strcat(buf, opts[i]); if(opts[i+1]) strcat(buf, "\n"); } lv_dropdown_set_options(dd, buf); }

这样切换语言时只需重新设置选项即可。

⚠️ 内存安全提醒
  • lv_dropdown_set_options()会复制字符串到内部缓冲区;
  • 缓冲区大小由LV_CFG_DROPDOWN_DEF_STR_MAX_LEN控制(默认256字节);
  • 超长会被截断,务必预估最大长度;
  • 若频繁更新选项,建议复用同一字符串缓冲区,避免碎片。

真实项目中的整合应用

让我们回到开头提到的医疗设备案例,看看如何将两者协同使用。

架构设计思路

主屏幕 ├── [List] 功能导航 │ ├── 设置 → 跳转设置页 │ ├── 校准 → 触发校准流程 │ └── 导出 → 弹出文件保存对话框 │ └── 状态栏 └── [Dropdown] 实时模式选择(待机 / 监测 / 报警)

页面跳转怎么做才规范?

别再用全局变量满天飞了。推荐使用轻量级页面栈:

#define MAX_PAGES 4 static lv_obj_t *page_stack[MAX_PAGES]; static uint8_t sp = 0; void push_screen(lv_obj_t *new_page) { if(sp > 0) lv_obj_add_flag(page_stack[sp-1], LV_OBJ_FLAG_HIDDEN); if(sp < MAX_PAGES) page_stack[sp++] = new_page; lv_obj_clear_flag(new_page, LV_OBJ_FLAG_HIDDEN); lv_scr_load(new_page); } void pop_screen(void) { if(sp <= 1) return; lv_obj_del(page_stack[--sp]); // 自动触发析构 lv_scr_load(page_stack[sp-1]); }

然后在 List 的事件回调中调用:

void on_settings_click(lv_event_t *e) { lv_obj_t *settings_page = create_settings_page(); // 工厂函数 push_screen(settings_page); }

是不是有点像移动端的 Activity 栈?这就是工程化思维的价值


常见坑点与调试秘籍

❌ 问题1:点击无反应?

检查是否注册了正确的事件类型:

// 错误 ❌ lv_obj_add_event_cb(obj, cb, LV_EVENT_PRESSED, NULL); // 正确 ✅ lv_obj_add_event_cb(obj, cb, LV_EVENT_CLICKED, NULL);

PRESSED是按下瞬间,CLICKED是完整点击(按下+释放)。大多数情况下应使用后者。

❌ 问题2:下拉菜单弹窗跑偏甚至黑屏?

原因通常是显存不足导致渲染失败

解决方案:

  • 减少LV_VER_RES或启用双缓冲降为单缓冲;
  • 限制 dropdown 最大高度:lv_dropdown_set_max_height(dd, 120);
  • 检查disp_drv.flush_cb是否正确实现,特别是DMA传输完成中断。

❌ 问题3:内存占用越来越高?

排查是否重复创建对象未删除。典型错误模式:

// 每次刷新都新建dropdown —— 内存泄漏! while(1) { lv_obj_t *dd = lv_dropdown_create(parent); // ... }

正确做法:创建一次,后续仅更新内容。


设计哲学:让UI服务于功能

最后分享几点来自一线项目的思考:

场景推荐方案
功能少于5项,常驻操作使用 List 直接展示
参数选择,选项固定Dropdown
数值调节,连续变化使用 Slider + Label 反馈
高频切换状态用 Toggle Button 或下拉结合图标

记住一句话:

最好的UI,是让用户感觉不到UI的存在

List 和 Dropdown 的意义,不仅是“画出来”,更是帮助开发者建立起结构化的交互模型——让复杂系统变得可预测、易操作。


写在最后

LVGL 不只是一个图形库,它是嵌入式世界里的“前端框架”。而 List 和 Dropdown,则是其中最常用也最容易被低估的两个组件。

当你下次接到一个HMI任务时,不妨先问自己几个问题:

  • 我的功能要不要分层?→ 用 List 构建导航。
  • 用户要不要做选择?→ 用 Dropdown 提供明确选项。
  • 设备有没有键盘?→ 加入 group 支持焦点导航。
  • 内存够不够?→ 控制字符串长度,避免频繁重建。

把这些细节揉进日常开发习惯里,你的嵌入式界面就会从“能用”走向“好用”,最终迈向“专业”。

如果你正在做类似项目,欢迎留言交流具体场景。也可以分享你在使用 List 和 Dropdown 时踩过的坑,我们一起避坑前行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1143148.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Keil5下载设置详解:STM32芯片支持包获取方法

Keil5下载设置详解&#xff1a;STM32芯片支持包获取与实战配置指南 在嵌入式开发的世界里&#xff0c;一个项目能否顺利启动&#xff0c;往往不取决于代码写得多优雅&#xff0c;而在于 开发环境是否正确搭建 。尤其是当你第一次打开Keil uVision5&#xff0c;准备为一块全新…

AutoGLM-Phone-9B性能评测:端侧AI模型对比

AutoGLM-Phone-9B性能评测&#xff1a;端侧AI模型对比 随着移动端AI应用的快速发展&#xff0c;如何在资源受限设备上实现高效、多模态的大模型推理成为业界关注的核心问题。传统大语言模型虽具备强大语义理解能力&#xff0c;但其高计算开销难以适配手机、IoT等边缘场景。为此…

终极系统清理指南:彻底清除Visual Studio残留文件

终极系统清理指南&#xff1a;彻底清除Visual Studio残留文件 【免费下载链接】VisualStudioUninstaller Visual Studio Uninstallation sometimes can be unreliable and often leave out a lot of unwanted artifacts. Visual Studio Uninstaller is designed to thoroughly …

完整指南:FanControl智能温控系统快速上手方案

完整指南&#xff1a;FanControl智能温控系统快速上手方案 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/fa/FanCon…

VIA键盘配置工具:零基础打造专属机械键盘的智能神器

VIA键盘配置工具&#xff1a;零基础打造专属机械键盘的智能神器 【免费下载链接】app 项目地址: https://gitcode.com/gh_mirrors/app8/app 还在为机械键盘的复杂设置而烦恼吗&#xff1f;VIA键盘配置工具让键盘定制变得像搭积木一样简单&#xff01;这款开源Web应用专…

VIA键盘配置工具:三步打造专属机械键盘的终极指南

VIA键盘配置工具&#xff1a;三步打造专属机械键盘的终极指南 【免费下载链接】app 项目地址: https://gitcode.com/gh_mirrors/app8/app 还在为机械键盘的复杂配置而烦恼吗&#xff1f;VIA键盘配置工具就是你的完美解决方案&#xff01;这款完全免费的开源Web应用让任…

CXPatcher深度解析:Mac完美运行Windows应用的技术实战指南

CXPatcher深度解析&#xff1a;Mac完美运行Windows应用的技术实战指南 【免费下载链接】CXPatcher A patcher to upgrade Crossover dependencies and improve compatibility 项目地址: https://gitcode.com/gh_mirrors/cx/CXPatcher CXPatcher作为macOS平台上专为Cross…

5分钟快速上手:AI文本生成平台oobabooga完整安装指南

5分钟快速上手&#xff1a;AI文本生成平台oobabooga完整安装指南 【免费下载链接】one-click-installers Simplified installers for oobabooga/text-generation-webui. 项目地址: https://gitcode.com/gh_mirrors/on/one-click-installers 还在为复杂的AI环境配置而烦恼…

基于HAL_UART_RxCpltCallback的双串口同步接收方案

用好一个回调函数&#xff0c;让双串口通信不再“丢包”——HAL库下高效接收实战 你有没有遇到过这样的场景&#xff1a;STM32一边通过串口1跟上位机通信&#xff0c;一边通过串口2读传感器数据。结果主循环里一加个 delay() 或者处理点复杂逻辑&#xff0c;串口2的数据就丢了…

赛马娘DMM版优化指南:从汉化到性能的完整解决方案

赛马娘DMM版优化指南&#xff1a;从汉化到性能的完整解决方案 【免费下载链接】umamusume-localify Localify "ウマ娘: Pretty Derby" DMM client 项目地址: https://gitcode.com/gh_mirrors/um/umamusume-localify 还在为赛马娘DMM版的日文界面困扰吗&#x…

高精度数字频率计设计:工业现场应用实战

高精度数字频率计实战设计&#xff1a;从工业现场痛点到系统级解决方案在某次风电设备巡检中&#xff0c;工程师发现一台变桨电机的转速监测数据频繁跳动&#xff0c;导致控制系统误判为“机械卡滞”而触发停机。现场排查数小时后才发现&#xff0c;问题并非出在电机本身&#…

铜钟音乐:重塑纯净聆听体验的数字绿洲

铜钟音乐&#xff1a;重塑纯净聆听体验的数字绿洲 【免费下载链接】tonzhon-music 铜钟 (Tonzhon.com): 免费听歌; 没有直播, 社交, 广告, 干扰; 简洁纯粹, 资源丰富, 体验独特&#xff01;(密码重置功能已回归) 项目地址: https://gitcode.com/GitHub_Trending/to/tonzhon-m…

TikTokDownload字幕提取神器:解锁视频文案的终极解决方案

TikTokDownload字幕提取神器&#xff1a;解锁视频文案的终极解决方案 【免费下载链接】TikTokDownload 抖音去水印批量下载用户主页作品、喜欢、收藏、图文、音频 项目地址: https://gitcode.com/gh_mirrors/ti/TikTokDownload 还在为手动记录抖音视频文案而耗费宝贵时间…

网易云音乐脚本使用指南:解锁5大隐藏功能提升听歌体验

网易云音乐脚本使用指南&#xff1a;解锁5大隐藏功能提升听歌体验 【免费下载链接】myuserscripts 油猴脚本:网易云音乐:云盘歌曲快传(含周杰伦),歌曲下载,转存云盘,云盘匹配纠正,听歌量打卡,本地上传云盘 咪咕音乐:歌曲下载 项目地址: https://gitcode.com/gh_mirrors/my/my…

Windows终极性能优化工具:Winhance中文版完整使用教程

Windows终极性能优化工具&#xff1a;Winhance中文版完整使用教程 【免费下载链接】Winhance-zh_CN A Chinese version of Winhance. PowerShell GUI application designed to optimize and customize your Windows experience. 项目地址: https://gitcode.com/gh_mirrors/wi…

PDF-Extract-Kit进阶:自定义输出模板开发指南

PDF-Extract-Kit进阶&#xff1a;自定义输出模板开发指南 1. 引言&#xff1a;为何需要自定义输出模板&#xff1f; 在实际的文档智能处理场景中&#xff0c;标准的JSON或LaTeX输出格式虽然结构清晰&#xff0c;但往往难以直接满足业务系统的集成需求。例如&#xff1a; 企业…

CXPatcher:Mac平台Windows应用兼容性优化方案

CXPatcher&#xff1a;Mac平台Windows应用兼容性优化方案 【免费下载链接】CXPatcher A patcher to upgrade Crossover dependencies and improve compatibility 项目地址: https://gitcode.com/gh_mirrors/cx/CXPatcher 在当今数字化工作环境中&#xff0c;跨平台应用兼…

PiP-Tool 画中画工具完整使用教程:轻松实现多窗口协同工作

PiP-Tool 画中画工具完整使用教程&#xff1a;轻松实现多窗口协同工作 【免费下载链接】PiP-Tool PiP tool is a software to use the Picture in Picture mode on Windows. This feature allows you to watch content (video for example) in thumbnail format on the screen …

科哥PDF-Extract-Kit保姆级教程:5分钟搭建智能文档处理系统

科哥PDF-Extract-Kit保姆级教程&#xff1a;5分钟搭建智能文档处理系统 1. 引言与学习目标 1.1 智能文档处理的现实挑战 在科研、教育和办公场景中&#xff0c;大量信息以 PDF 文档形式存在。传统手动提取文本、公式、表格的方式效率低下&#xff0c;尤其面对扫描件或复杂版…

PDF-Extract-Kit实战指南:专利文献关键信息提取

PDF-Extract-Kit实战指南&#xff1a;专利文献关键信息提取 1. 引言 1.1 专利文献处理的挑战与需求 在科研、知识产权分析和技术创新领域&#xff0c;专利文献是最重要的技术资料之一。然而&#xff0c;专利文档通常以PDF格式发布&#xff0c;结构复杂&#xff0c;包含大量非…