嵌入式物联网智能硬件嵌入式GUI硬件开发【免费下载链接】HoloCubic带网络功能的伪全息透明显示桌面站项目地址https://gitcode.com/gh_mirrors/ho/HoloCubic点击查看免费下载本篇技术指南围绕 HoloCubic 仓库中 LVGL 示例文档 lv_ex_switch/index.rst 展开系统讲解 LVGLSwitch开关组件的创建、状态切换、事件回调、部件样式与底层实现原理。读完本文你将掌握在 HoloCubic 这类嵌入式 UI 中正确启用并调用lv_switch_*系列 API、处理LV_EVENT_VALUE_CHANGED事件、以及基于lv_bar的部件体系定制开关外观的完整方法。1. 文档定位一份“Simple Switch”示例索引关联文档位于 LVGL 示例体系src/lv_examples/src/lv_ex_widgets/lv_ex_switch/目录下是 LVGL 组件示例索引reStructuredText文件。文档结构非常简洁包含两个要点Simple SwitchC 示例通过.. lv_example:: lv_ex_widgets/lv_ex_switch/lv_ex_switch_1指令引用对应的 C 示例文件 lv_ex_switch_1.c这是 RST 文档体系与示例代码自动关联的标准写法MicroPython文档标注 “No examples yet.”尚无示例。不过需要指出的是当前仓库中实际已提供对应实现 lv_ex_switch_1.py且该 Python 版本比 C 版本更进一步展示了完整的部件样式定制流程详见第 6 节。也就是说这份文档的真正技术内核是它引用的lv_ex_switch_1示例——一个用最简代码演示开关组件完整生命周期的入门范例。2. C 示例逐行精读创建、复制与事件回调示例核心代码 lv_ex_switch_1.c 全文仅 25 行含预处理是学习 Switch 组件的最佳起点。完整代码及逐段解读如下#include ../../../lv_examples.h #include stdio.h #if LV_USE_SWITCH static void event_handler(lv_obj_t * obj, lv_event_t event) { if(event LV_EVENT_VALUE_CHANGED) { printf(State: %s\n, lv_switch_get_state(obj) ? On : Off); } } void lv_ex_switch_1(void) { /*Create a switch and apply the styles*/ lv_obj_t *sw1 lv_switch_create(lv_scr_act(), NULL); lv_obj_align(sw1, NULL, LV_ALIGN_CENTER, 0, -50); lv_obj_set_event_cb(sw1, event_handler); /*Copy the first switch and turn it ON*/ lv_obj_t *sw2 lv_switch_create(lv_scr_act(), sw1); lv_switch_on(sw2, LV_ANIM_ON); lv_obj_align(sw2, NULL, LV_ALIGN_CENTER, 0, 50); } #endif关键点拆解如下编译开关整个示例被#if LV_USE_SWITCH包裹只有开启该宏默认值为 1才会参与编译这是 LVGL 示例体系的一贯约定。lv_switch_create(lv_scr_act(), NULL)以当前活动屏幕为父对象创建第一个开关。copy参数传NULL表示全新创建默认尺寸为LV_DPX(60) × LV_DPX(35)取值范围固定为 0~1见第 4 节源码分析。lv_obj_align(sw1, NULL, LV_ALIGN_CENTER, 0, -50)将开关 1 居中对齐并向上偏移 50 像素lv_obj_align的偏移单位是像素在LV_DPX()缩放环境下一般用LV_DPX(n)保证 DPI 适配。lv_obj_set_event_cb(sw1, event_handler)为开关 1 注册事件回调。回调中只监听LV_EVENT_VALUE_CHANGED值变化事件——这是开关组件最核心的事件在用户点击切换状态时由底层信号函数触发详见第 5 节。lv_switch_create(lv_scr_act(), sw1)第二个开关通过“复制对象”的方式创建以sw1作为copy参数传入。LVGL 会拷贝源对象的状态与样式同时新对象获得独立的扩展数据见 lv_switch.c 的 copy 分支。lv_switch_on(sw2, LV_ANIM_ON)将复制出的开关 2 以带动画的方式打开LV_ANIM_ON表示滑块平滑滑动传入LV_ANIM_OFF则立即切换、无过渡动画。lv_obj_align(sw2, NULL, LV_ALIGN_CENTER, 0, 50)开关 2 居中并向下偏移 50 像素与开关 1 形成上下对称的视觉效果。运行行为程序运行后屏幕中央出现两个开关上方开关 1 默认处于关闭Off状态下方开关 2 默认处于开启On状态。用手指或触控笔点击任一开关开关滑块滑动并翻转状态串口printf同步输出一行状态信息State: On State: Offlv_switch_get_state(obj)返回boolfalse表示 OFFtrue表示 ON——它的底层实现其实是读取 bar 组件的值是否等于 1见第 4 节。3. 组件 API 全景创建、状态机与内联查询关联文档引用的示例只用到了lv_switch_create、lv_switch_on、lv_switch_get_state三个函数但完整的 Switch 组件 API 定义在头文件 lv_switch.h 中覆盖创建、状态切换、动画与查询全流程API签名功能说明lv_switch_createlv_obj_t * lv_switch_create(lv_obj_t * par, const lv_obj_t * copy)创建开关par为父对象copy非 NULL 时复制该开关lv_switch_onvoid lv_switch_on(lv_obj_t * sw, lv_anim_enable_t anim)打开开关anim为LV_ANIM_ON带动画、LV_ANIM_OFF立即切换lv_switch_offvoid lv_switch_off(lv_obj_t * sw, lv_anim_enable_t anim)关闭开关动画参数同上lv_switch_togglebool lv_switch_toggle(lv_obj_t * sw, lv_anim_enable_t anim)翻转开关状态返回翻转后的新状态lv_switch_get_statebool lv_switch_get_state(const lv_obj_t * sw)读取当前状态falseOFF、trueON内联函数底层调用lv_bar_get_value(sw) 1lv_switch_set_anim_timevoid lv_switch_set_anim_time(lv_obj_t * sw, uint16_t anim_time)设置动画时长毫秒内联转发给lv_bar_set_anim_timelv_switch_get_anim_timeuint16_t lv_switch_get_anim_time(const lv_obj_t * sw)读取动画时长同样转发给 bar 组件其中lv_switch_get_state与lv_switch_set_anim_time是static inline函数直接映射到 bar 组件接口这一设计印证了“Switch 是 Bar 的语义化封装”这一组件关系见下一节。三个可独立设置样式的部件从 lv_switch.h 的部件枚举可以看出开关由三个部件组成LV_SWITCH_PART_BG开关背景继承自LV_BAR_PART_BGLV_SWITCH_PART_INDIC开关的填充指示区域继承自LV_BAR_PART_INDICLV_SWITCH_PART_KNOB滑块Switch 特有的虚拟部件枚举值由_LV_BAR_PART_VIRTUAL_LAST续接。正因如此第 6 节的 MicroPython 样式示例才能对背景、指示条、滑块开/关四种场景分别设置样式。4. 底层实现为什么它是“带滑块的 Bar”Switch 并不是从零实现的独立控件而是基于lv_bar进度条扩展而来。源码 lv_switch.c 提供了确凿证据创建路径lv_switch_create内部首先调用lv_bar_create(par, copy)创建祖先对象再通过lv_obj_allocate_ext_attr追加lv_switch_ext_t扩展数据其中只新增了一个lv_switch_ext_t结构体包含lv_bar_ext_t bar与lv_style_list_t style_knob两个成员。默认配置创建时lv_obj_set_click(sw, true)使控件可点击尺寸设为LV_DPX(60) × LV_DPX(35)并通过lv_bar_set_range(sw, 0, 1)把值域压缩为 0~1——因此“开关状态”本质就是 bar 的 0/1 取值这也是lv_switch_get_state用lv_bar_get_value(sw) 1判断的原因。状态同步lv_switch_on在设置lv_bar_set_value(sw, 1, anim)的同时调用lv_obj_add_state(sw, LV_STATE_CHECKED)添加“选中”状态lv_switch_off则对称地设置值 0 并清除LV_STATE_CHECKED。该状态位在主题中用于改变指示区颜色实现开/关的视觉区分。绘制逻辑lv_switch_designlv_switch.c先调用祖先 bar 的绘制函数画出背景与指示条再根据ext-bar.indic_area的宽度按比例计算滑块knob的矩形区域滑块位置与指示区宽度正相关指示区越宽滑块越靠右同时还考虑LV_SWITCH_PART_KNOB上的内边距使滑块可以呈现“悬浮”效果。RTL 布局下滑块位置计算会自动镜像。这一设计带来的直接收益是Switch 无需重写滑块以外的绘制代码且天然继承 bar 的指示条样式能力。5. 事件机制状态变化的完整调用链示例中的event_handler只关心LV_EVENT_VALUE_CHANGED。该事件由信号函数 lv_switch_signal 统一派发主要有两条触发路径触摸释放LV_SIGNAL_RELEASED用户点击开关完成释放时先依据当前状态调用lv_switch_off或lv_switch_on完成切换带动画随后lv_event_send(sw, LV_EVENT_VALUE_CHANGED, NULL)广播值变化事件——示例回调即在此刻被调用并打印新状态方向键控制LV_SIGNAL_CONTROL当LV_USE_GROUP开启、开关被加入对象组时LV_KEY_RIGHT/LV_KEY_UP打开开关、LV_KEY_LEFT/LV_KEY_DOWN关闭开关随后同样发送LV_EVENT_VALUE_CHANGED。这为旋钮encoder、键盘等非触摸输入设备如 lv_demo_keypad_encoder.c 中把开关加入选择器组提供了完整的可访问性支持。另外LV_SIGNAL_GET_EDITABLE分支明确把开关标记为“不可编辑”避免它与 bar/slider 祖先在对象组编辑逻辑上冲突。6. MicroPython 版本四段式样式定制范例关联文档虽标注 MicroPython “No examples yet”但仓库实际提供了 lv_ex_switch_1.py。它与 C 版运行效果一致两个开关上下对称但额外演示了如何用样式 API 定制开关外观弥补了 C 版“只建控件、不改样式”的空白值得完整展开def event_handler(obj, event): if event lv.EVENT.VALUE_CHANGED: print(State: %s % (On if obj.get_state() else Off)) # 背景样式高圆角胶囊外形 上下内边距 bg_style lv.style_t() lv.style_copy(bg_style, lv.style_pretty) bg_style.body.radius 800 bg_style.body.padding.top 6 bg_style.body.padding.bottom 6 # 指示条样式圆角胶囊 统一浅蓝色 indic_style lv.style_t() lv.style_copy(indic_style, lv.style_pretty_color) indic_style.body.radius 800 indic_style.body.main_color lv.color_hex(0x9fc8ef) indic_style.body.grad_color lv.color_hex(0x9fc8ef) # 去掉各方向内边距让指示条贴边 # 滑块关闭样式圆角 底部阴影 knob_off_style lv.style_t() lv.style_copy(knob_off_style, lv.style_pretty) knob_off_style.body.radius 800 knob_off_style.body.shadow.width 4 knob_off_style.body.shadow.type lv.SHADOW.BOTTOM # 滑块开启样式带主题色填充 底部阴影 knob_on_style lv.style_t() lv.style_copy(knob_on_style, lv.style_pretty_color) knob_on_style.body.radius 800 knob_on_style.body.shadow.width 4 knob_on_style.body.shadow.type lv.SHADOW.BOTTOM sw1 lv.sw(lv.scr_act()) sw1.set_style(lv.sw.STYLE.BG, bg_style) sw1.set_style(lv.sw.STYLE.INDIC, indic_style) sw1.set_style(lv.sw.STYLE.KNOB_ON, knob_on_style) sw1.set_style(lv.sw.STYLE.KNOB_OFF, knob_off_style) sw1.align(None, lv.ALIGN.CENTER, 0, -50) sw1.set_event_cb(event_handler) sw2 lv.sw(lv.scr_act(), sw1) sw2.on(lv.ANIM.ON) sw2.align(None, lv.ALIGN.CENTER, 0, 50) sw2.set_event_cb(lambda o, e: None)该示例映射到 C 语言部件体系时的要点bg_style.body.radius 800极大圆角值使矩形在宽度大于高度时呈现胶囊形开关的经典外观这一技巧在 C 侧对应lv_style_set_radius(style, LV_STATE_DEFAULT, 800)指示条main_color与grad_color均设为0x9fc8ef无渐变浅蓝并以 0 内边距贴边对应LV_SWITCH_PART_INDIC的填充样式滑块开启/关闭分别设置独立样式KNOB_ON/KNOB_OFF对应 C 侧基于LV_SWITCH_PART_KNOB的本地样式与LV_STATE_CHECKED状态配合——开启时滑块带有主题色填充style_pretty_color关闭时退化为普通浅色style_prettysw2.set_event_cb(lambda o, e: None)用空回调覆盖复制来源sw1的事件回调避免复制对象连带打印日志是复制创建对象时需要注意的细节。7. 在 HoloCubic 固件中启用与集成 SwitchHoloCubic 固件2.Firmware/HoloCubic-fw通过 PlatformIO LVGL 驱动 240×240 彩屏其 LVGL 配置位于 lv_conf.hSwitch 组件相关的依赖项均已默认开启/*Slider (dependencies: lv_bar)*/ #define LV_USE_SLIDER 1 /*Switch (dependencies: lv_slider)*/ #define LV_USE_SWITCH 1同时 lv_conf.h 中LV_USE_ANIMATION为 1保证LV_ANIM_ON的滑动过渡动画生效。若需在自有工程中启用 Switch必须同时满足LV_USE_SWITCH 1Switch 开关LV_USE_SLIDER 1Switch 的编译期硬依赖。lv_switch.c 与 lv_switch.h 中均有如下硬性检查未开启会在编译期直接报错#if LV_USE_SLIDER 0 #error lv_sw: lv_slider is required. Enable it in lv_conf.h (LV_USE_SLIDER 1) #endif同仓库的二次佐证Switch 在 LVGL 官方示例中被多处实战调用可作为 API 用法的补充参考lv_demo_widgets.c创建开关并绑定事件回调用lv_switch_on(sw, LV_ANIM_OFF)根据主题标志初始化状态在回调里通过lv_switch_get_state(sw)读取结果后切换 Material 主题的明暗标志LV_THEME_MATERIAL_FLAG_DARK——这是“开关控制模式切换”的典型范式与 HoloCubic 桌面站的显示模式切换场景高度契合lv_demo_stress.c循环创建开关、lv_switch_on(obj, LV_ANIM_ON)后立刻复制新对象并lv_switch_off(obj, LV_ANIM_ON)用于验证动画与复制路径的内存稳定性lv_demo_keypad_encoder.c将开关放入选择器组验证方向键/旋钮输入路径。8. 小结lv_ex_switch示例虽短却完整覆盖了 Switch 组件的四大核心主题创建与复制lv_switch_create的copy参数、状态切换与动画lv_switch_on/off/toggle与LV_ANIM_ON/OFF、事件处理LV_EVENT_VALUE_CHANGED与lv_switch_get_state回读、以及三部件样式体系BG/INDIC/KNOB。底层实现上Switch 是lv_bar的语义化扩展0~1 值域 滑块绘制依赖LV_USE_SLIDER与LV_USE_ANIMATION两个配置项这一设计让它能以极低成本获得成熟的主题与输入支持。对 HoloCubic 开发者而言参考该示例即可在伪全息桌面站的设置页中快速落地开关类交互如模式切换、亮屏策略开关等功能。赞分享嵌入式物联网智能硬件嵌入式GUI硬件开发【免费下载链接】HoloCubic带网络功能的伪全息透明显示桌面站项目地址https://gitcode.com/gh_mirrors/ho/HoloCubic点击查看免费下载相关推荐HoloCubic 固件中的 LVGL Switch 开关控件实战解析从 lv_ex_switch 示例到源码级原理HoloCubic 固件中的 LVGL Switch 开关控件实战解析从 lv_ex_switch 示例到源码级原理 本文以 LVGL 官方示例 lv_ex_嵌入式物联网智能硬件嵌入式GUI硬件开发HoloCubic 固件中的 LVGL LED 控件实战基于 lv_ex_led 示例的亮度控制与自定义样式解析HoloCubic 固件中的 LVGL LED 控件实战基于 lv_ex_led 示例的亮度控制与自定义样式解析 本篇技术指南以 HoloCubic 固件携带嵌入式物联网智能硬件嵌入式GUI硬件开发pydub快速上手5分钟学会导入、保存与播放音频文件附10个实战示例pydub快速上手5分钟学会导入、保存与播放音频文件附10个实战示例 pydub 是一个用 Python 处理音频的轻量级库提供简单易懂的高级接口让你嵌入式物联网智能硬件嵌入式GUI硬件开发上一篇2025物联网区块链开发工程师招聘指南从设备到去中心化应用的全栈机遇下一篇Reggaeton Be Gone容器化部署使用Docker简化环境配置创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?