
嵌入式物联网智能硬件嵌入式GUI硬件开发【免费下载链接】HoloCubic带网络功能的伪全息透明显示桌面站项目地址https://gitcode.com/gh_mirrors/ho/HoloCubic点击查看免费下载本文以 HoloCubic 开源仓库中 LVGL 示例文档 lv_ex_msgbox/index.rst 为核心深入讲解 LVGL 消息框Message box /lv_msgbox组件的两种典型用法——基础消息框与模态对话框并结合仓库内的 C 示例、Python 移植示例以及lv_msgbox源码实现给出完整的 API 说明与配置依赖解析。读完本文你将能够在 HoloCubic 这类基于 LVGL 7.x 的嵌入式 GUI 项目中独立创建带按钮的消息框、捕获按钮点击事件、实现带半透明遮罩的模态弹窗并理解其内部布局与自动关闭机制。1. 文档与示例概览index.rst位于 LVGL 示例目录 lv_examples/src/lv_ex_widgets/lv_ex_msgbox/ 下是 LVGL 官方示例文档中针对消息框组件的一页索引。它按三部分组织章节主题对应示例Simple Message box基础消息框文本 多个按钮lv_ex_msgbox_1Modal模态消息框全屏半透明遮罩 动画lv_ex_msgbox_2MicroPythonMicroPython 版本示例暂无No examples yetHoloCubic 固件中随 LVGL 一起打包的是LVGL 7.9.1见 lvgl.h 中LVGL_VERSION_MAJOR/MINOR/PATCH定义。两个示例均以 C 语言实现同时各自提供了对应的 MicroPython.py版本文档中的 MicroPython 一节声明暂无独立示例实际 Python 移植代码就放在示例目录内。两个示例的注册信息同时出现在 examples.txt 与 lv_ex_widgets.h 中说明它们是 LVGL 示例体系内正式收录的组件演示。2. 示例一Simple Message box基础消息框2.1 完整代码lv_ex_msgbox_1.c 的完整内容如下#include ../../../lv_examples.h #include stdio.h #if LV_USE_MSGBOX static void event_handler(lv_obj_t * obj, lv_event_t event) { if(event LV_EVENT_VALUE_CHANGED) { printf(Button: %s\n, lv_msgbox_get_active_btn_text(obj)); } } void lv_ex_msgbox_1(void) { static const char * btns[] {Apply, Close, }; lv_obj_t * mbox1 lv_msgbox_create(lv_scr_act(), NULL); lv_msgbox_set_text(mbox1, A message box with two buttons.); lv_msgbox_add_btns(mbox1, btns); lv_obj_set_width(mbox1, 200); lv_obj_set_event_cb(mbox1, event_handler); lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0); /*Align to the corner*/ } #endif2.2 关键点逐行解析按钮描述数组必须以空字符串结尾。btns[] {Apply, Close, }中最后一个是按钮矩阵Button matrix的终止标记不是第三个按钮。按钮描述数组的完整约束见 lv_msgbox.h 中lv_msgbox_add_btns的注释btn_mapbutton descriptor (button matrix map)。例如const char *txt[] {ok, close, }不能是局部变量。注意代码中特意用static const char *声明因为按钮文字需要在整个生命周期内有效。创建与初始化顺序先用lv_msgbox_create(lv_scr_act(), NULL)在活动屏幕上创建消息框第二个参数copy传NULL表示从零创建而非复制某个已有对象随后通过lv_msgbox_set_text设置正文、lv_msgbox_add_btns添加按钮、lv_obj_set_width指定宽度200 像素、lv_obj_set_event_cb挂载事件回调最后lv_obj_align居中显示。事件处理消息框按钮被点击后消息框会发出LV_EVENT_VALUE_CHANGED事件。示例回调中通过lv_msgbox_get_active_btn_text(obj)获取被点击按钮的文本并用printf打印到串口。该函数在 lv_msgbox.h 中的语义是获取用户最后激活按下、释放等的按钮文本常用于event_cb中内部封装了对按钮矩阵lv_btnmatrix_get_active_btn_text的调用见 lv_msgbox.c。示例的运行效果见官方渲染图 lv_ex_msgbox_1.png居中的消息框显示一行正文与两个并排按钮。2.3 对应 Python 实现lv_ex_msgbox_1.py 提供了逐行对应的 MicroPython 版本def event_handler(obj, event): if event lv.EVENT.VALUE_CHANGED: print(Button: %s % lv.mbox.get_active_btn_text(obj)) btns [Apply, Close, ] mbox1 lv.mbox(lv.scr_act()) mbox1.set_text(A message box with two buttons.) mbox1.add_btns(btns) mbox1.set_width(200) mbox1.set_event_cb(event_handler) mbox1.align(None, lv.ALIGN.CENTER, 0, 0) # Align to the cornerPython 版 API 与 C 版一一对应lv.mbox(...)↔lv_msgbox_create便于在没有 C 工具链的仿真环境如仓库内的 LvglSimulator中快速验证交互逻辑。3. 示例二Modal模态消息框3.1 完整代码lv_ex_msgbox_2.c 演示了如何实现模态效果——弹窗出现时用户无法再与背后的界面交互#include ../../../lv_examples.h #if LV_USE_MSGBOX static void mbox_event_cb(lv_obj_t *obj, lv_event_t evt); static void btn_event_cb(lv_obj_t *btn, lv_event_t evt); static void opa_anim(void * bg, lv_anim_value_t v); static lv_obj_t *mbox, *info; static lv_style_t style_modal; static const char welcome_info[] Welcome to the modal message box demo!\n Press the button to display a message box.; static const char in_msg_info[] Notice that you cannot touch the button again while the message box is open.; void lv_ex_msgbox_2(void) { lv_style_init(style_modal); lv_style_set_bg_color(style_modal, LV_STATE_DEFAULT, LV_COLOR_BLACK); /* Create a button, then set its position and event callback */ lv_obj_t *btn lv_btn_create(lv_scr_act(), NULL); lv_obj_set_size(btn, 200, 60); lv_obj_set_event_cb(btn, btn_event_cb); lv_obj_align(btn, NULL, LV_ALIGN_IN_TOP_LEFT, 20, 20); /* Create a label on the button */ lv_obj_t *label lv_label_create(btn, NULL); lv_label_set_text(label, Display a message box!); /* Create an informative label on the screen */ info lv_label_create(lv_scr_act(), NULL); lv_label_set_text(info, welcome_info); lv_label_set_long_mode(info, LV_LABEL_LONG_BREAK); /* Make sure text will wrap */ lv_obj_set_width(info, LV_HOR_RES - 10); lv_obj_align(info, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 5, -5); } static void mbox_event_cb(lv_obj_t *obj, lv_event_t evt) { if(evt LV_EVENT_DELETE obj mbox) { /* Delete the parent modal background */ lv_obj_del_async(lv_obj_get_parent(mbox)); mbox NULL; /* happens before object is actually deleted! */ lv_label_set_text(info, welcome_info); } else if(evt LV_EVENT_VALUE_CHANGED) { /* A button was clicked */ lv_msgbox_start_auto_close(mbox, 0); } } static void btn_event_cb(lv_obj_t *btn, lv_event_t evt) { if(evt LV_EVENT_CLICKED) { /* Create a full-screen background */ /* Create a base object for the modal background */ lv_obj_t *obj lv_obj_create(lv_scr_act(), NULL); lv_obj_reset_style_list(obj, LV_OBJ_PART_MAIN); lv_obj_add_style(obj, LV_OBJ_PART_MAIN, style_modal); lv_obj_set_pos(obj, 0, 0); lv_obj_set_size(obj, LV_HOR_RES, LV_VER_RES); static const char * btns2[] {Ok, Cancel, }; /* Create the message box as a child of the modal background */ mbox lv_msgbox_create(obj, NULL); lv_msgbox_add_btns(mbox, btns2); lv_msgbox_set_text(mbox, Hello world!); lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); lv_obj_set_event_cb(mbox, mbox_event_cb); /* Fade the message box in with an animation */ lv_anim_t a; lv_anim_init(a); lv_anim_set_var(a, obj); lv_anim_set_time(a, 500); lv_anim_set_values(a, LV_OPA_TRANSP, LV_OPA_50); lv_anim_set_exec_cb(a, (lv_anim_exec_xcb_t)opa_anim); lv_anim_start(a); lv_label_set_text(info, in_msg_info); lv_obj_align(info, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 5, -5); } } static void opa_anim(void * bg, lv_anim_value_t v) { lv_obj_set_style_local_bg_opa(bg, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, v); } #endif3.2 模态的关键实现手法模态的本质是把消息框作为全屏遮罩对象的子对象使遮罩层拦截所有触摸事件。代码分三步实现创建全屏遮罩在按钮点击回调btn_event_cb中先在活动屏幕创建一个普通lv_obj清除其默认样式lv_obj_reset_style_list套用纯黑色背景样式style_modal并铺满整个屏幕lv_obj_set_size(obj, LV_HOR_RES, LV_VER_RES)。黑色背景样式在lv_ex_msgbox_2()中预先初始化lv_style_init(style_modal); lv_style_set_bg_color(style_modal, LV_STATE_DEFAULT, LV_COLOR_BLACK);将消息框挂到遮罩之下lv_msgbox_create(obj, NULL)以遮罩对象为父节点创建消息框因此弹窗只会在遮罩层上呈现背后的按钮不可触摸——这正是提示文案in_msg_info中 you cannot touch the button again while the message box is open 的含义。淡入动画通过 LVGL 动画模块让遮罩从LV_OPA_TRANSP全透明渐变为LV_OPA_5050% 半透明时长 500ms。动画执行回调opa_anim逐帧调用lv_obj_set_style_local_bg_opa更新遮罩透明度。3.3 生命周期管理删除与自动关闭模态弹窗的销毁逻辑集中在mbox_event_cb中包含两个分支LV_EVENT_VALUE_CHANGED按钮被点击调用lv_msgbox_start_auto_close(mbox, 0)delay传 0 表示立即触发关闭流程。从源码看lv_msgbox_start_auto_close 在启用动画LV_USE_ANIMATION时会为消息框播放宽高收缩动画收缩结束后执行lv_msgbox_close_ready_cb删除对象动画时长由lv_msgbox_get_anim_time(mbox)决定默认值LV_MSGBOX_CLOSE_ANIM_TIME为 200ms见 lv_msgbox.c。LV_EVENT_DELETE消息框被删除此时必须异步删除遮罩父对象lv_obj_del_async(lv_obj_get_parent(mbox))否则在删除回调中同步删除父对象会导致悬垂指针随后将mbox置NULL注释特别提醒该赋值发生在对象真正删除之前并恢复底部提示文案。这里展示了一个通用模式父-子对象组合销毁时子对象的事件回调里要用lv_obj_del_async清理父节点这在嵌入式 GUI 中是避免崩溃的关键细节。3.4 对应 Python 实现lv_ex_msgbox_2.py 将模态逻辑封装成一个Modal(lv.mbox)子类构造时创建全屏黑色遮罩bg在default_callback中同样处理DELETE删除父遮罩与VALUE_CHANGEDstart_auto_close(0)事件并预留了用户回调插槽是 Python 端复用的典范。模态示例的渲染效果见 lv_ex_msgbox_2.png半透明黑色背景覆盖整个屏幕消息框居中浮于其上。4. lv_msgbox 完整 API 速查lv_msgbox.h 定义了消息框组件的全部对外接口按其功能分组4.1 创建与按钮函数说明lv_obj_t * lv_msgbox_create(lv_obj_t * par, const lv_obj_t * copy)创建消息框。par为父对象屏幕或其他容器copy非 NULL 时从已有对象复制void lv_msgbox_add_btns(lv_obj_t * mbox, const char * btn_map[])添加按钮。btn_map必须以结尾的按钮矩阵映射数组且不能是局部变量4.2 文本与行为设置函数说明void lv_msgbox_set_text(lv_obj_t * mbox, const char * txt)设置消息框正文void lv_msgbox_set_text_fmt(lv_obj_t * mbox, const char * fmt, ...)以printf风格格式化正文如动态拼接字符串/数值void lv_msgbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time)设置关闭动画时长ms0 表示无动画void lv_msgbox_start_auto_close(lv_obj_t * mbox, uint16_t delay)延时delay毫秒后自动关闭删除消息框void lv_msgbox_stop_auto_close(lv_obj_t * mbox)停止自动关闭流程void lv_msgbox_set_recolor(lv_obj_t * mbox, bool en)开启/关闭按钮文字重着色必须在lv_msgbox_add_btns之后调用4.3 查询函数说明const char * lv_msgbox_get_text(const lv_obj_t * mbox)获取当前正文文本uint16_t lv_msgbox_get_active_btn(lv_obj_t * mbox)获取最后激活的按钮索引未设置时返回LV_BTNMATRIX_BTN_NONEconst char * lv_msgbox_get_active_btn_text(lv_obj_t * mbox)获取最后激活按钮的文本未设置时返回 NULLuint16_t lv_msgbox_get_anim_time(const lv_obj_t * mbox)获取关闭动画时长bool lv_msgbox_get_recolor(const lv_obj_t * mbox)查询重着色是否开启lv_obj_t * lv_msgbox_get_btnmatrix(lv_obj_t * mbox)获取内部按钮矩阵对象在调用lv_msgbox_add_btns之前返回 NULL其中lv_msgbox_get_active_btn的取值逻辑值得注意它会优先返回按钮矩阵中被激活的按钮 id若为LV_BTNMATRIX_BTN_NONE则回退到当前聚焦按钮 id见 lv_msgbox.c这意味着通过键盘/编码器Encoder聚焦导航时同样能取到当前按钮。5. 内部实现原理5.1 对象结构lv_msgbox_ext_tlv_msgbox.h展示了消息框的组合结构typedef struct { lv_cont_ext_t bg; /*Ext. of ancestor*/ /*New data for this type */ lv_obj_t * text; /*Text of the message box*/ lv_obj_t * btnm; /*Button matrix for the buttons*/ #if LV_USE_ANIMATION uint16_t anim_time; /*Duration of close animation [ms] (0: no animation)*/ #endif } lv_msgbox_ext_t;消息框在继承lv_cont容器布局能力的基础上内部由两个子对象构成text一个lv_label默认对齐方式LV_LABEL_ALIGN_CENTER、换行模式LV_LABEL_LONG_BREAK、默认文本 Message见 lv_msgbox.cbtnm一个lv_btnmatrix按钮矩阵用于容纳多个按钮并在创建时统一设置为LV_BTNMATRIX_CTRL_CLICK_TRIG | LV_BTNMATRIX_CTRL_NO_REPEAT点击即触发、长按不重复见 lv_msgbox.c。5.2 布局重排mbox_realign消息框的尺寸与内部布局由mbox_realignlv_msgbox.c统一维护正文标签宽度跟随消息框宽度按钮矩阵的高度则根据按钮行数、字体行高与各部件内边距动态计算。它会遍历按钮映射数组遇到以\n开头的行就累加行数实现多行按钮布局。当消息框宽度变化LV_SIGNAL_COORD_CHG或样式变化LV_SIGNAL_STYLE_CHG时会自动触发重排。5.3 事件转发与默认行为按钮矩阵 → 消息框lv_msgbox_btnm_event_cblv_msgbox.c把按钮矩阵的PRESSED / RELEASED / CLICKED / VALUE_CHANGED等事件原样转发给消息框因此消息框挂载的事件回调能收到这些事件默认自动关闭lv_msgbox_default_event_cblv_msgbox.c是创建时默认注册的回调——任何按钮被激活都会调用lv_msgbox_start_auto_close(mbox, 0)自动关闭消息框。示例二覆盖了该回调以自定义行为键盘导航适配在LV_USE_GROUP使能时消息框的信号处理会把编码器输入的LV_KEY_UP/DOWN转换为LV_KEY_LEFT/RIGHT并同步按钮矩阵的聚焦/编辑状态lv_msgbox.c保证无触摸屏场景下可用方向键/编码器操作按钮。5.4 部件Part体系消息框定义了三个可独立设置样式的部件lv_msgbox.h部件含义LV_MSGBOX_PART_BG消息框整体背景等于LV_CONT_PART_MAINLV_MSGBOX_PART_BTN_BG按钮区域按钮矩阵背景LV_MSGBOX_PART_BTN单个按钮Material 主题对消息框背景的默认样式在 lv_theme_material.c 中定义阴影宽度LV_DPX(50)、阴影颜色随主题明暗切换这也是基础示例中消息框带投影观感的来源。6. 配置开关与依赖6.1 使能宏消息框默认开启在 HoloCubic 固件打包的 LVGL 配置 lv_conf.h 中/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ #define LV_USE_MSGBOX 1lv_conf_template.h 中同样默认为 1。若使用 Kconfig 构建Zephyr 等对应选项为 Kconfig 中的LV_USE_MSGBOX它自动依赖LV_USE_RECT、LV_USE_BTNM、LV_USE_LABEL三个子选项。6.2 硬性依赖检查lv_msgbox.h 在编译期做了三重强制检查缺失任一依赖都会直接报错#if LV_USE_CONT 0 #error lv_mbox: lv_cont is required. Enable it in lv_conf.h (LV_USE_CONT 1) #endif #if LV_USE_BTNMATRIX 0 #error lv_mbox: lv_btnm is required. Enable it in lv_conf.h (LV_USE_BTNMATRIX 1) #endif #if LV_USE_LABEL 0 #error lv_mbox: lv_label is required. Enable it in lv_conf.h (LV_USE_LABEL 1) #endif因此在裁剪 LVGL 功能时若保留消息框必须同步保留LV_USE_CONT、LV_USE_BTNMATRIX、LV_USE_LABEL三个依赖项LV_USE_MSGBOX通过 lv_conf_internal.h 的默认分支兜底为 1。7. 在 HoloCubic 项目中的落点从源码结构看HoloCubic 固件的主程序位于 src/main.cpp、gui_guider.c、setup_scr_home.c等当前这些业务源码尚未直接调用lv_msgbox_create消息框组件目前以 LVGL 库能力的形式随固件一并编译可用LV_USE_MSGBOX已开启。若要在 HoloCubic 的伪全息屏幕上增加确认弹窗设置保存提示等交互可直接复用本示例的两种模式轻量提示照搬lv_ex_msgbox_1在事件回调里读取lv_msgbox_get_active_btn_text分支处理不同按钮阻塞式确认照搬lv_ex_msgbox_2的全屏遮罩 子消息框 lv_obj_del_async清理父遮罩结构实现不可穿透的模态确认框并可用lv_msgbox_set_text_fmt动态填充 Wi-Fi 连接状态、日期时间等运行时信息HoloCubic 的 network.cpp 与 display.cpp 是此类信息的主要来源。也可在仓库的 Windows 仿真工程 LvglSimulator 中先以 SDL 窗口快速验证消息框布局与交互再移植到 ESP32 固件缩短开发迭代周期。8. 小结围绕 lv_ex_msgbox/index.rst 这一文档索引本文完整还原了 LVGL 7.9.1 消息框组件的两个官方示例lv_ex_msgbox_1展示从创建、设文本、加按钮到事件回调的完整链路lv_ex_msgbox_2展示以全屏遮罩实现模态、以动画实现淡入、以lv_obj_del_async安全清理父对象的进阶玩法。配合lv_msgbox的 API 全景、内部组合结构、事件转发与布局重排机制以及配置依赖检查读者可以在此基础上直接为 HoloCubic 这类嵌入式 GUI 项目设计消息提示与模态确认交互。赞分享嵌入式物联网智能硬件嵌入式GUI硬件开发【免费下载链接】HoloCubic带网络功能的伪全息透明显示桌面站项目地址https://gitcode.com/gh_mirrors/ho/HoloCubic点击查看免费下载相关推荐HoloCubic 中的 LVGL Message Box消息框实战简单消息框与模态对话框的 C / MicroPython 双语言实现HoloCubic 中的 LVGL Message Box消息框实战简单消息框与模态对话框的 C / MicroPython 双语言实现 本文以 Holo嵌入式物联网智能硬件嵌入式GUI硬件开发X-TRACK 的 LVGL 消息框lv_msgbox控件实战指南创建、事件与源码剖析X TRACK 的 LVGL 消息框lv_msgbox控件实战指南创建、事件与源码剖析 导读 消息框Message Box, lv_msgbox 是智能硬件嵌入式硬件开发HoloCubic 固件中的 lv_msgbox 消息框Simple 与 Modal 两种形态的完整实战指南HoloCubic 固件中的 lv_msgbox 消息框Simple 与 Modal 两种形态的完整实战指南 导读 本文以 HoloCubic 仓库中 lvg嵌入式物联网智能硬件嵌入式GUI硬件开发上一篇TDengine 产品与技术全景面向工业物联网的高性能云原生时序数据库下一篇TencentDB-Agent-Memory 数据迁移实战v2 → v3 租户隔离表结构升级与 L2/L3 文件重定位创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考