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

用LVGL给你的嵌入式设备做个登录界面吧(附完整代码和事件处理逻辑)

从零构建LVGL嵌入式登录界面实战代码与架构设计在智能家居面板、工业HMI等嵌入式设备中用户认证功能几乎是标配需求。本文将手把手教你如何利用LVGLLight and Versatile Graphics Library为嵌入式设备构建一个功能完整的登录界面包含记住密码、自动登录等实用功能。我们将从架构设计开始逐步深入到每个组件的实现细节最后给出可直接复用的完整代码。1. 项目架构设计与核心组件一个典型的LVGL登录界面通常由以下几个核心模块组成用户界面层负责渲染所有可视化元素业务逻辑层处理用户认证、状态管理数据持久层存储记住的密码等配置信息1.1 技术选型与开发环境对于嵌入式GUI开发我们需要考虑以下技术组合技术组件选型建议备注硬件平台STM32F4/F7/H7系列带LCD控制器和足够RAM显示驱动LVGL v8.x当前稳定版本输入设备电阻/电容触摸屏或编码器按键组合存储方案SPI Flash或EEPROM用于保存用户配置开发环境VSCodePlatformIO或Keil MDK/STM32CubeIDE1.2 界面元素分解登录界面需要包含以下UI组件typedef struct { lv_obj_t *screen; // 主屏幕容器 lv_obj_t *username_label; // 用户名标签 lv_obj_t *password_ta; // 密码输入框 lv_obj_t *login_btn; // 登录按钮 lv_obj_t *remember_cb; // 记住密码复选框 lv_obj_t *autologin_cb; // 自动登录复选框 lv_obj_t *keyboard; // 虚拟键盘 } login_ui_t;2. 核心功能实现2.1 密码输入与键盘交互密码输入需要特殊处理以确保安全性// 设置密码框属性 lv_textarea_set_password_mode(ui-password_ta, true); lv_textarea_set_password_bullet(ui-password_ta, •); lv_textarea_set_one_line(ui-password_ta, true); lv_textarea_set_max_length(ui-password_ta, 16); // 键盘与输入框关联 lv_keyboard_set_textarea(ui-keyboard, ui-password_ta); lv_obj_add_event_cb(ui-password_ta, ta_event_cb, LV_EVENT_ALL, ui-keyboard);键盘事件回调函数需要处理焦点变化static void ta_event_cb(lv_event_t *e) { lv_event_code_t code lv_event_get_code(e); lv_obj_t *ta lv_event_get_target(e); lv_obj_t *kb lv_event_get_user_data(e); if(code LV_EVENT_FOCUSED) { lv_keyboard_set_textarea(kb, ta); lv_obj_clear_flag(kb, LV_OBJ_FLAG_HIDDEN); } else if(code LV_EVENT_DEFOCUSED) { lv_keyboard_set_textarea(kb, NULL); lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN); } }2.2 记住密码功能实现密码存储需要考虑安全性即使是在嵌入式设备上// 非安全示例实际项目应加密 #define CONFIG_ADDR 0x08080000 // Flash最后一页 typedef struct { char password[32]; bool remember; bool autologin; } user_config_t; void save_config(user_config_t *cfg) { FLASH_Unlock(); FLASH_ErasePage(CONFIG_ADDR); FLASH_ProgramWord(CONFIG_ADDR, *(uint32_t*)cfg); FLASH_Lock(); } void load_config(user_config_t *cfg) { memcpy(cfg, (void*)CONFIG_ADDR, sizeof(user_config_t)); }2.3 自动登录逻辑自动登录需要延时处理以避免界面闪烁static void auto_login_timer_cb(lv_timer_t *timer) { login_ui_t *ui timer-user_data; if(ui-autologin) { lv_event_send(ui-login_btn, LV_EVENT_CLICKED, NULL); } lv_timer_del(timer); } // 在界面初始化时启动定时器 if(autologin_enabled) { lv_timer_create(auto_login_timer_cb, 1500, ui); }3. 完整代码实现3.1 界面初始化void login_ui_init(login_ui_t *ui) { // 创建主容器 ui-screen lv_obj_create(NULL); lv_obj_set_size(ui-screen, 480, 320); lv_obj_set_style_bg_color(ui-screen, lv_color_hex(0xf0f0f0), 0); // 用户名标签 ui-username_label lv_label_create(ui-screen); lv_label_set_text(ui-username_label, admindevice.local); lv_obj_set_pos(ui-username_label, 50, 80); // 密码输入框 ui-password_ta lv_textarea_create(ui-screen); lv_obj_set_size(ui-password_ta, 300, 50); lv_obj_set_pos(ui-password_ta, 50, 120); // ...设置密码框属性 // 记住密码复选框 ui-remember_cb lv_checkbox_create(ui-screen); lv_checkbox_set_text(ui-remember_cb, Remember Password); lv_obj_set_pos(ui-remember_cb, 50, 180); // 自动登录复选框 ui-autologin_cb lv_checkbox_create(ui-screen); lv_checkbox_set_text(ui-autologin_cb, Auto Login); lv_obj_set_pos(ui-autologin_cb, 200, 180); // 登录按钮 ui-login_btn lv_btn_create(ui-screen); lv_obj_set_size(ui-login_btn, 150, 50); lv_obj_set_pos(ui-login_btn, 165, 240); lv_obj_t *label lv_label_create(ui-login_btn); lv_label_set_text(label, Login); // 虚拟键盘 ui-keyboard lv_keyboard_create(ui-screen); lv_obj_add_flag(ui-keyboard, LV_OBJ_FLAG_HIDDEN); // 加载保存的配置 user_config_t cfg; load_config(cfg); if(cfg.remember) { lv_textarea_set_text(ui-password_ta, cfg.password); lv_obj_add_state(ui-remember_cb, LV_STATE_CHECKED); } if(cfg.autologin) { lv_obj_add_state(ui-autologin_cb, LV_STATE_CHECKED); } }3.2 事件处理系统void login_events_init(login_ui_t *ui) { // 登录按钮事件 lv_obj_add_event_cb(ui-login_btn, login_event_cb, LV_EVENT_CLICKED, ui); // 复选框事件 lv_obj_add_event_cb(ui-remember_cb, checkbox_event_cb, LV_EVENT_VALUE_CHANGED, ui); lv_obj_add_event_cb(ui-autologin_cb, checkbox_event_cb, LV_EVENT_VALUE_CHANGED, ui); } static void login_event_cb(lv_event_t *e) { login_ui_t *ui lv_event_get_user_data(e); const char *pwd lv_textarea_get_text(ui-password_ta); // 验证密码 if(strcmp(pwd, default123) 0) { // 实际项目应从安全存储读取 // 保存配置 user_config_t cfg { .remember lv_obj_has_state(ui-remember_cb, LV_STATE_CHECKED), .autologin lv_obj_has_state(ui-autologin_cb, LV_STATE_CHECKED) }; strncpy(cfg.password, cfg.remember ? pwd : , sizeof(cfg.password)); save_config(cfg); // 跳转到主界面 show_main_screen(); } else { lv_obj_add_state(ui-password_ta, LV_STATE_INVALID); } } static void checkbox_event_cb(lv_event_t *e) { lv_obj_t *cb lv_event_get_target(e); login_ui_t *ui lv_event_get_user_data(e); // 自动登录需要记住密码 if(cb ui-autologin_cb lv_obj_has_state(cb, LV_STATE_CHECKED)) { lv_obj_add_state(ui-remember_cb, LV_STATE_CHECKED); } }4. 高级功能扩展4.1 密码强度验证在登录按钮事件中添加密码策略检查typedef enum { WEAK, // 纯数字或小于6位 MEDIUM, // 字母数字8位以上 STRONG // 字母数字特殊字符12位以上 } password_strength_t; password_strength_t check_password_strength(const char *pwd) { bool has_digit false, has_alpha false, has_special false; size_t len strlen(pwd); for(size_t i 0; i len; i) { if(isdigit(pwd[i])) has_digit true; else if(isalpha(pwd[i])) has_alpha true; else has_special true; } if(len 12 has_digit has_alpha has_special) return STRONG; if(len 8 has_digit has_alpha) return MEDIUM; return WEAK; }4.2 多语言支持利用LVGL的文本索引功能实现国际化// 在翻译文件中 static const char *translations[][2] { {Login, 登录}, {Remember Password, 记住密码}, // ... }; const char *get_translation(const char *text) { for(size_t i 0; i sizeof(translations)/sizeof(translations[0]); i) { if(strcmp(translations[i][0], text) 0) { return translations[i][1]; // 返回对应语言文本 } } return text; }4.3 动画效果增强为界面切换添加动画void show_login_screen() { lv_obj_t *act_scr lv_scr_act(); lv_obj_fade_out(act_scr, 300, 0); lv_scr_load_anim(ui.screen, LV_SCR_LOAD_ANIM_MOVE_TOP, 300, 0, false); } void show_main_screen() { lv_obj_t *main_scr create_main_screen(); lv_obj_fade_out(ui.screen, 300, 0); lv_scr_load_anim(main_scr, LV_SCR_LOAD_ANIM_FADE_ON, 300, 0, false); }5. 性能优化与调试技巧5.1 内存优化策略嵌入式设备资源有限需要特别注意对象池管理重复使用UI对象而非频繁创建销毁样式共享多个对象共用相同样式减少内存占用部分刷新只更新变化的区域而非整个屏幕// 样式共享示例 static lv_style_t style_btn; lv_style_init(style_btn); lv_style_set_bg_color(style_btn, lv_color_hex(0x2195f6)); lv_obj_add_style(ui-login_btn, style_btn, 0); lv_obj_add_style(ui-back_btn, style_btn, 0);5.2 常见问题排查触摸无响应检查触摸控制器初始化确认触摸信号线连接正确校准触摸参数// 触摸调试示例 void touch_debug() { lv_indev_t *indev lv_indev_get_next(NULL); lv_indev_data_t data; lv_indev_read(indev, data); printf(Touch at (%d,%d) %s\n, data.point.x, data.point.y, data.state LV_INDEV_STATE_PR ? PRESS : RELEASE); }界面卡顿检查是否在UI线程执行耗时操作减少不必要的重绘优化图像资源尺寸6. 安全增强方案6.1 密码安全存储实际产品中应采用加密存储#include mbedtls/aes.h void encrypt_password(char *out, const char *in) { mbedtls_aes_context aes; unsigned char key[16] securekey123456; // 应从安全区域获取 unsigned char iv[16] {0}; mbedtls_aes_setkey_enc(aes, key, 128); mbedtls_aes_crypt_cbc(aes, MBEDTLS_AES_ENCRYPT, strlen(in)1, iv, (const unsigned char*)in, (unsigned char*)out); }6.2 防暴力破解机制static uint8_t failed_attempts 0; static uint32_t last_attempt_time 0; bool check_login_attempt() { uint32_t now lv_tick_get(); if(now - last_attempt_time 30000) { // 30秒超时重置 failed_attempts 0; } if(failed_attempts 3) { lv_label_set_text(ui-status_label, Too many attempts, wait 30s); return false; } failed_attempts; last_attempt_time now; return true; }7. 项目移植指南7.1 硬件适配层不同硬件平台需要实现以下接口// 显示接口 void disp_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) { // 将color_p缓冲区内容写入到area指定的显示区域 } // 触摸接口 void touch_read(lv_indev_drv_t *drv, lv_indev_data_t *data) { // 读取触摸坐标并填充到data结构 } // 系统时钟 uint32_t custom_tick_get(void) { return HAL_GetTick(); // 使用硬件定时器 }7.2 资源管理建议将图片、字体等资源组织为单独模块resources/ ├── images/ │ ├── logo.c │ └── background.c ├── fonts/ │ ├── montserrat_16.c │ └── simsun_24.c └── resources.h在项目实践中我发现最影响开发效率的往往是调试环节。建议在开发初期就建立完善的日志系统同时保留SWD/JTAG调试接口。当遇到界面显示异常时可以先检查LVGL的返回值和处理状态大多数问题都能通过LVGL的日志输出找到线索。

相关文章:

用LVGL给你的嵌入式设备做个登录界面吧(附完整代码和事件处理逻辑)

从零构建LVGL嵌入式登录界面:实战代码与架构设计 在智能家居面板、工业HMI等嵌入式设备中,用户认证功能几乎是标配需求。本文将手把手教你如何利用LVGL(Light and Versatile Graphics Library)为嵌入式设备构建一个功能完整的登录…...

Jetson Orin音频开发避坑指南:手把手教你用amixer配置AHUB音频路由(附常见问题排查)

Jetson Orin音频开发实战:从零构建AHUB音频路由的完整指南 当你在Orin开发板上完成声卡驱动加载后,却发现扬声器依然沉默无声——这种挫败感每个嵌入式音频开发者都深有体会。问题的根源往往在于AHUB(Audio Hub)这个音频集线器的路…...

深度学习模型评估指标:从原理到实践

1. 深度学习模型评估指标全解析在训练完一个深度学习模型后,很多开发者常犯的错误是只关注准确率(Accuracy)这一个指标。上周我review团队项目时,就发现一个目标检测模型虽然准确率达到92%,但实际部署后漏检率高达30%——这正是因为忽略了召回…...

MinerU 系列教程 附录:速查手册与参考索引

MinerU 系列教程 附录篇 本附录汇集了 MinerU v3.0.9 日常开发和运维中最常查阅的四类参考信息:CLI 命令速查、环境变量配置、后端选择决策矩阵,以及项目核心文件索引。你可以把它当作一份"随手翻"的工具手册,在遇到具体问题时快速…...

MinerU 系列教程 第二十七课:核心算法深度剖析

MinerU 系列教程 第二十七篇 本篇教程作为 模块九:源码篇 - 设计模式与核心算法 的第二课,将深入分析 MinerU v3.0.9 中七个关键算法的实现细节。上一课我们从设计模式角度理解了 MinerU 的架构哲学,本课将聚焦算法层面——从阅读顺序排序到 LaTeX 后处理状态机,逐一剖析这…...

机器学习概率预测评估:对数损失、布里尔分数与ROC AUC详解

1. 概率评分方法概述在机器学习分类问题中,预测概率而非简单的类别标签能够提供更丰富的信息和不确定性度量。这种概率预测方式允许我们使用更精细的评估指标来解读和验证模型输出的可靠性。这些评估方法通常被称为评分规则(scoring rules)或评分函数(scoring funct…...

MinerU 系列教程 第二十六课:设计模式在 MinerU 中的应用

MinerU 系列教程 第二十六篇 本篇教程作为 模块九:源码篇 - 设计模式与核心算法 的第一课,将深入剖析 MinerU 源码中实际运用的六种经典设计模式。不同于教科书式的抽象讲解,我们将直接阅读 MinerU v3.0.9 的真实代码,理解每种模式在文档智能解析系统中的具体作用和实现细节…...

丢包率不高但应用仍然卡顿?一次基于 tcpdump +RTT抽样的网络性能排障实战

丢包率不高但应用仍然卡顿?一次基于 tcpdump RTT 抽样的网络性能排障实战 在很多生产环境里,网络问题最容易被“表面指标”误导。监控看起来并不糟:带宽没打满、CPU 没爆、接口错误包不多、平均丢包率也几乎为零,但业务侧就是持续…...

AndroidX迁移指南:如何将XBanner适配到最新Android项目

AndroidX迁移指南:如何将XBanner适配到最新Android项目 【免费下载链接】XBanner :fire:【图片轮播】支持图片无限轮播,支持AndroidX、自定义指示点、显示提示文字、切换动画、自定义布局,一屏多显、视频图片混合轮播等功能 项目地址: http…...

Mate Engine未来路线图展望:即将到来的新功能

Mate Engine未来路线图展望:即将到来的新功能 【免费下载链接】Mate-Engine A free Desktop Mate alternative with a lightweight interface and custom VRM support, though with more features. 项目地址: https://gitcode.com/gh_mirrors/ma/Mate-Engine …...

代价敏感学习在分类不平衡问题中的应用与实践

1. 不平衡分类问题的现实挑战在信贷欺诈检测场景中,正常交易占比可能高达99.9%,而欺诈交易仅占0.1%。传统分类器即使将所有样本预测为正常,也能获得99.9%的准确率——这种表面上的高性能完全掩盖了模型在实际业务中的失效。这正是类别不平衡问…...

3步解决Void编辑器构建时的依赖地狱:从报错到编译通过的实战指南

3步解决Void编辑器构建时的依赖地狱:从报错到编译通过的实战指南 【免费下载链接】void 开源AI代码编辑器,Cursor的替代方案。 项目地址: https://gitcode.com/GitHub_Trending/void2/void Void作为开源AI代码编辑器的新星,为开发者提…...

基于NVIDIA Nemotron构建安全语音问答助手的全栈实践

1. 从零构建具备安全防护的语音问答助手:基于NVIDIA Nemotron的全栈实践去年CES展会上NVIDIA发布的Nemotron模型家族,为我们构建下一代智能助手提供了全新可能。不同于简单的API调用,真正的智能助手需要将语音识别、多模态检索、安全过滤和长…...

3分钟掌握抖音下载器:免费批量下载抖音无水印视频的终极指南

3分钟掌握抖音下载器:免费批量下载抖音无水印视频的终极指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback…...

终极指南:用llama2.c轻松加载Meta Llama 2与自定义模型,告别复杂部署

终极指南:用llama2.c轻松加载Meta Llama 2与自定义模型,告别复杂部署 【免费下载链接】llama2.c Inference Llama 2 in one file of pure C 项目地址: https://gitcode.com/GitHub_Trending/ll/llama2.c llama2.c是一个轻量级开源项目&#xff0c…...

突破连续控制难题:深度确定性策略梯度(DDPG)实战指南

突破连续控制难题:深度确定性策略梯度(DDPG)实战指南 【免费下载链接】Reinforcement-learning-with-tensorflow Simple Reinforcement learning tutorials, 莫烦Python 中文AI教学 项目地址: https://gitcode.com/gh_mirrors/re/Reinforcement-learning-with-ten…...

超简单llama2.c量化优化:参数迭代调优实战指南

超简单llama2.c量化优化:参数迭代调优实战指南 【免费下载链接】llama2.c Inference Llama 2 in one file of pure C 项目地址: https://gitcode.com/GitHub_Trending/ll/llama2.c llama2.c是一个轻量级的Llama 2推理框架,用纯C语言实现&#xff…...

2025全新指南:零代码优化AI代理的Azure搜索服务配置

2025全新指南:零代码优化AI代理的Azure搜索服务配置 【免费下载链接】ai-agents-for-beginners 12 Lessons to Get Started Building AI Agents 项目地址: https://gitcode.com/GitHub_Trending/ai/ai-agents-for-beginners 在AI应用开发中,Azure…...

告别繁琐输入:AutoGPT Agent运行模态框的智能优化方案

告别繁琐输入:AutoGPT Agent运行模态框的智能优化方案 【免费下载链接】AutoGPT AutoGPT is the vision of accessible AI for everyone, to use and to build on. Our mission is to provide the tools, so that you can focus on what matters. 项目地址: https…...

避开ns-3学习深坑:用sns3模块快速搭建GEO卫星通信仿真(附GitHub代码解读)

从零玩转卫星通信仿真:sns3模块极简上手指南 第一次打开ns-3的文档时,我盯着满屏的C代码和复杂的拓扑配置参数,感觉像是面对一座需要徒手攀登的悬崖。直到发现了欧空局开发的sns3模块——这个专为卫星通信设计的仿真工具包,才让GE…...

Abseil线程安全终极指南:多线程环境下的高效并发编程实践

Abseil线程安全终极指南:多线程环境下的高效并发编程实践 【免费下载链接】abseil-cpp Abseil Common Libraries (C) 项目地址: https://gitcode.com/GitHub_Trending/ab/abseil-cpp Abseil C库提供了全面的线程安全解决方案,帮助开发者在多线程环…...

手把手教你解决Elsevier LaTeX投稿的‘File not found’报错(附cas-dc模板实战)

攻克Elsevier LaTeX投稿中的"File not found"陷阱:从报错解析到实战修复 当你满怀期待地将精心撰写的学术论文通过Elsevier系统提交,却遭遇冰冷的"File not found"报错时,那种挫败感我深有体会。作为经历过数十次Elsevie…...

5个超级实用的Bash-Oneliner进程管理技巧:从监控到控制的全流程指南

5个超级实用的Bash-Oneliner进程管理技巧:从监控到控制的全流程指南 【免费下载链接】Bash-Oneliner A collection of handy Bash One-Liners and terminal tricks for data processing and Linux system maintenance. 项目地址: https://gitcode.com/GitHub_Tren…...

彻底解决fmtlib/fmt中back_inserter调用难题:从原理到实战修复

彻底解决fmtlib/fmt中back_inserter调用难题:从原理到实战修复 【免费下载链接】fmt A modern formatting library 项目地址: https://gitcode.com/GitHub_Trending/fm/fmt fmtlib/fmt作为一款现代格式化库,以其高效、安全的特性被广泛应用于C项目…...

顺序表(动态数组)实现详解:从原理到接口设计(面试视角)

目录 一、整体认知 二、数据结构设计 面试要点 三、生命周期管理 1. 初始化 2. 销毁 四、扩容机制(核心) 深度理解(面试高频) 1. 为什么用 realloc? 2. 为什么按 2 倍扩容? 3. 为什么用 tmp? 五…...

Bash-Oneliner终极指南:10个Terminal Tricks让效率倍增的完整教程

Bash-Oneliner终极指南:10个Terminal Tricks让效率倍增的完整教程 【免费下载链接】Bash-Oneliner A collection of handy Bash One-Liners and terminal tricks for data processing and Linux system maintenance. 项目地址: https://gitcode.com/GitHub_Trendi…...

Python指南python-guide深度:安全编码与漏洞防范终极指南

Python指南python-guide深度:安全编码与漏洞防范终极指南 【免费下载链接】python-guide Python best practices guidebook, written for humans. 项目地址: https://gitcode.com/gh_mirrors/py/python-guide Python作为一种强大且灵活的编程语言&#xff0…...

Vue3 + Element-UI项目里,手把手教你搞定TinyMCE 6本地化部署(告别API-Key和云服务报错)

Vue3 Element-UI项目实战:TinyMCE 6完整本地化集成指南 在后台管理系统开发中,富文本编辑器是不可或缺的核心组件。当Vue3遇上Element-UI,再结合TinyMCE 6的强大编辑能力,本应成就完美的技术组合。但现实往往充满挑战——云服务依…...

7个AFFiNE代码审查最佳实践:提升协作效率与代码质量的完整指南

7个AFFiNE代码审查最佳实践:提升协作效率与代码质量的完整指南 【免费下载链接】AFFiNE There can be more than Notion and Miro. AFFiNE(pronounced [ə‘fain]) is a next-gen knowledge base that brings planning, sorting and creating all together. Privacy…...

别再为Unity WebGL部署头疼了!一份Tomcat/Nginx通用的服务器配置清单

Unity WebGL部署全攻略:Tomcat与Nginx服务器配置精要 当Unity开发者完成WebGL版本的构建后,真正的挑战往往才开始——如何让这些文件在服务器上正常运行。不同于本地开发环境,生产服务器的配置差异可能导致各种意料之外的问题,从资…...