news 2026/10/19 9:55:01

LVGL Spinbox 数值微调控件实战:从示例代码到源码实现全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LVGL Spinbox 数值微调控件实战:从示例代码到源码实现全解析
  • 嵌入式
  • 物联网
  • 智能硬件
  • 嵌入式GUI
  • 硬件开发

【免费下载链接】HoloCubic

带网络功能的伪全息透明显示桌面站

项目地址:https://gitcode.com/gh_mirrors/ho/HoloCubic
点击查看免费下载

导读:本文以 HoloCubic 开源仓库中 LVGL 官方示例文档 index.rst 及其对应示例lv_ex_spinbox_1为主体,深入剖析 LVGL v7 中 Spinbox(数值微调控件)的创建、配置、交互与底层实现原理。读完本文,你将掌握 Spinbox 的全部核心 API(范围、数字格式、步进、回绕、光标定位),理解其基于 Textarea 的继承设计与格式化输出逻辑,并能在 HoloCubic 这类嵌入式 LVGL 项目中直接落地可运行的参数设置界面。

一、示例文档与代码位置

该文档位于仓库 LVGL 组件示例目录:

  • 文档入口:index.rst,标题为Simple Spinbox,通过.. lv_example::指令引用 C 示例。
  • C 示例源码:lv_ex_spinbox_1.c
  • 示例声明:lv_ex_widgets.h 中导出void lv_ex_spinbox_1(void);
  • 运行截图:lv_ex_spinbox_1.png

需要说明的是:index.rst在 MicroPython 小节标注 "No examples yet",但示例目录中实际已存在 lv_ex_spinbox_1.py(详见本文第七节),本文将以 C 版为主线、Python 版为补充展开讲解。

上图即lv_ex_spinbox_1的运行效果:中间为数值显示框(当前显示+00.150,其中青色高亮竖条所在的数字5是当前选中待编辑的数位),左右两侧各有一个圆角方块按钮(左侧为减号,右侧为加号,右侧按钮处于焦点高亮状态)。这与示例代码中"两侧按钮 + 中间 Spinbox"的布局完全对应。

二、在 HoloCubic 工程中启用 Spinbox

Spinbox 的启用开关定义在 LVGL 配置文件 lv_conf.h:

#define LV_USE_SPINBOX 1

依赖关系在 lv_spinbox.h 中做了强制校验:Spinbox 继承自 Textarea,因此必须同时启用文本框组件:

#if LV_USE_TEXTAREA == 0 #error "lv_spinbox: lv_ta is required. Enable it in lv_conf.h (LV_USE_TEXTAREA 1) " #endif

HoloCubic 仓库固件目录2.Firmware/HoloCubic-fw/lib/lvgl下内置了同版本的 LVGL 库,其lv_conf.h同样将LV_USE_SPINBOX置 1,因此上述示例与 API 在该固件环境中开箱即用。

三、Simple Spinbox 示例逐行拆解

以下为lv_ex_spinbox_1的完整源码(位于 lv_ex_spinbox_1.c,以#if LV_USE_SPINBOX保护,未启用时整段被剔除):

static lv_obj_t * spinbox; static void lv_spinbox_increment_event_cb(lv_obj_t * btn, lv_event_t e) { if(e == LV_EVENT_SHORT_CLICKED || e == LV_EVENT_LONG_PRESSED_REPEAT) { lv_spinbox_increment(spinbox); } } static void lv_spinbox_decrement_event_cb(lv_obj_t * btn, lv_event_t e) { if(e == LV_EVENT_SHORT_CLICKED || e == LV_EVENT_LONG_PRESSED_REPEAT) { lv_spinbox_decrement(spinbox); } } void lv_ex_spinbox_1(void) { spinbox = lv_spinbox_create(lv_scr_act(), NULL); lv_spinbox_set_range(spinbox, -1000, 90000); lv_spinbox_set_digit_format(spinbox, 5, 2); lv_spinbox_step_prev(spinbox); lv_obj_set_width(spinbox, 100); lv_obj_align(spinbox, NULL, LV_ALIGN_CENTER, 0, 0); lv_coord_t h = lv_obj_get_height(spinbox); lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL); lv_obj_set_size(btn, h, h); lv_obj_align(btn, spinbox, LV_ALIGN_OUT_RIGHT_MID, 5, 0); lv_theme_apply(btn, LV_THEME_SPINBOX_BTN); lv_obj_set_style_local_value_str(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_SYMBOL_PLUS); lv_obj_set_event_cb(btn, lv_spinbox_increment_event_cb); btn = lv_btn_create(lv_scr_act(), btn); lv_obj_align(btn, spinbox, LV_ALIGN_OUT_LEFT_MID, -5, 0); lv_obj_set_event_cb(btn, lv_spinbox_decrement_event_cb); lv_obj_set_style_local_value_str(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_SYMBOL_MINUS); }

3.1 创建与初始化

lv_spinbox_create(lv_scr_act(), NULL)以当前屏幕为父对象创建一个新的 Spinbox。从 lv_spinbox.c 的创建函数可以看到,它内部首先调用lv_textarea_create(),再通过lv_obj_allocate_ext_attr()追加 Spinbox 专有扩展数据,随后设置默认值:value=0、digit_count=5、step=1、range_min/max=±99999、rollover=false,并应用LV_THEME_SPINBOX主题。默认显示 5 位整数(dec_point_pos=0表示无小数点)。

3.2 范围与数字格式

lv_spinbox_set_range(spinbox, -1000, 90000); lv_spinbox_set_digit_format(spinbox, 5, 2);
  • set_range:设置取值区间[-1000, 90000](闭区间,边界包含)。底层实现会同步钳制当前值:lv_spinbox.c 中若value > range_max则令value = range_max,反之亦然,然后触发lv_spinbox_updatevalue()刷新显示。
  • set_digit_format(5, 2):digit_count=5表示数字总位数(不含小数点与符号);separator_position=2表示小数点前有 2 位整数,即格式为XX.XXX(2 位整数 + 3 位小数)。实现中对参数做了防御性约束(lv_spinbox.c):位数上限LV_SPINBOX_MAX_DIGIT_COUNT=10;若separator_position >= digit_count则自动置 0(退化为纯整数);且当位数小于 10 时,会把范围钳制在±(10^digit_count - 1)内,避免显示溢出。

示例中范围上限 90000 虽然只有 5 位,但正值方向实际上限是 99999,符合10^5 - 1的约束。

3.3 步进方向:step_prev 的作用

lv_spinbox_step_prev(spinbox);

这是本示例最容易被忽略的一行。step(步长)决定一次增/减操作改变多少值,同时决定光标当前停留在哪一位。step_prev()将步长乘以 10(lv_spinbox.c),即把编辑目标从"个位"上移到"更高一位"。

结合默认step=1:调用step_prev()后step=10,光标落在十位,后续每次increment/decrement改变 10。步长上移受范围限制:new_step不能超过max(|range_max|, |range_min|),在本例中即 90000,因此步长最多到 10000。对应地,step_next()将步长除以 10(不小于 1),把编辑位向低位移动(lv_spinbox.c)。

3.4 加减按钮与事件回调

按钮与 Spinbox 等高(h = lv_obj_get_height(spinbox)),分别通过LV_ALIGN_OUT_RIGHT_MID和LV_ALIGN_OUT_LEFT_MID对齐到 Spinbox 的左右两侧,间距 5px。

两个回调分别处理LV_EVENT_SHORT_CLICKED(单击)和LV_EVENT_LONG_PRESSED_REPEAT(长按重复触发)——这意味着按住按钮不放即可连续加减,这正是 Spinbox 适合做"快速调值"交互的原因。注意:第二个按钮通过lv_btn_create(lv_scr_act(), btn)复制第一个按钮创建,因此继承了尺寸、主题等属性,只需重新设置对齐、事件回调和符号(LV_SYMBOL_MINUS)。

按钮应用了LV_THEME_SPINBOX_BTN主题:在 lv_theme_material.c 中,该主题为按钮主部件添加背景与点击态样式;同时lv_theme.c的LV_THEME_SPINBOX分支会为 Spinbox 的背景(LV_SPINBOX_PART_BG)和光标(LV_SPINBOX_PART_CURSOR)应用主题样式(lv_theme.c)。

四、Spinbox 核心 API 速查

以下接口均声明于 lv_spinbox.h,对应实现位于 lv_spinbox.c:

分类函数说明
创建lv_spinbox_create(par, copy)创建 Spinbox;copy非空时复制既有实例
数值lv_spinbox_set_value(spinbox, i)直接设置值(越界自动钳制,实现)
数值lv_spinbox_get_value(spinbox)返回int32_t整数值;带小数格式时需自行除以10^(小数位数)换算为浮点
格式lv_spinbox_set_digit_format(spinbox, digit_count, separator_position)总位数与小数点位置;separator_position=0表示整数模式
范围lv_spinbox_set_range(spinbox, range_min, range_max)闭区间取值范围
步进lv_spinbox_set_step(spinbox, step)设置单次增减步长
步进lv_spinbox_step_next()/lv_spinbox_step_prev()步长 /10 或 ×10,控制编辑位向低/高位移动
步进lv_spinbox_increment()/lv_spinbox_decrement()按当前步长加/减一次
回绕lv_spinbox_set_rollover(spinbox, b)/lv_spinbox_get_rollover(spinbox)启用后到达边界会回绕到另一端(默认关闭)
填充lv_spinbox_set_padding_left(spinbox, padding)符号与首个数字之间插入padding个空格,用于对齐显示

样式部分定义了两个部件(lv_spinbox.h):LV_SPINBOX_PART_BG(背景,继承 Textarea 的背景部件)与LV_SPINBOX_PART_CURSOR(光标,复用LV_TEXTAREA_PART_CURSOR),可通过lv_obj_set_style_*系列接口按部件定制外观。

五、源码原理:继承自 Textarea 的数值编辑器

5.1 扩展数据结构

Spinbox 的专有状态全部存放在lv_spinbox_ext_t(lv_spinbox.h)中,它以lv_textarea_ext_t ta作为首个成员,从而完整继承文本框的扩展数据(文本缓冲、光标位置等):

typedef struct { lv_textarea_ext_t ta; /*Ext. of ancestor*/ int32_t value; int32_t range_max; int32_t range_min; int32_t step; uint8_t rollover : 1; uint16_t digit_count : 4; uint16_t dec_point_pos : 4; /*0 表示无小数点,纯整数*/ uint16_t digit_padding_left : 4; } lv_spinbox_ext_t;

5.2 格式化输出逻辑

lv_spinbox_updatevalue()(lv_spinbox.c)是 Spinbox 的显示核心,每次数值/步长/格式变化后都会执行,流程如下:

  1. 符号处理:仅当range_min < 0时显示+/-前缀(正值范围则隐藏符号,并让光标左移一位);
  2. 左填充:写入digit_padding_left个空格;
  3. 前导补零:将数值转为无符号数字串后,在左侧补0至digit_count位;
  4. 小数点插入:按dec_point_pos切分整数部分与小数部分,在中间写入.;
  5. 刷新文本:通过lv_textarea_set_text()输出;
  6. 光标定位:根据当前step的十进制数量级计算光标应停留的位,若该位在小数点之后则额外跳过小数点。

举例:示例初始值 0、格式5,2、无填充,输出为+00.000;截图中的+00.150即交互(单击加号 15 次)后的状态,其中5所在位是当前step=10对应的十位(小数第二位),被光标高亮——这与示例调用step_prev()将步长设为 10 的行为完全吻合。

5.3 增量/减量、零交叉与回绕

increment/decrement(lv_spinbox.c)的实现包含两个值得注意的细节:

  • 零交叉特殊模式:当从负值跨过 0 时,结果取绝对值的相反符号。例如当前值为-3、步长 10,value + step = 7 > 0且value < 0,则先令value = -(-3) = 3再叠加步长,得到13——即跨零后直接跳到正区间对应位,避免出现-0.000这类显示。
  • 回绕(rollover):未启用时越界直接饱和到边界值;启用后,当value == range_max时继续加会回到range_min(减同理反向回绕)。

5.4 输入控制:键盘与旋转编码器

在信号处理函数lv_spinbox_signal()(lv_spinbox.c)中,Spinbox 完整接入了 LVGL 的输入体系:

  • LV_SIGNAL_CONTROL(按键):LV_KEY_RIGHT对编码器执行increment、对其他输入执行step_next;LV_KEY_LEFT对应decrement/step_prev;LV_KEY_UP/LV_KEY_DOWN直接增/减;其他按键会透传给文本框添加字符(lv_textarea_add_char)。
  • LV_SIGNAL_RELEASED(释放):若是编码器且在编辑模式下,释放一次会切换到下一位编辑(step_next),当步长已为 1 时则从最高位重新开始循环;若为指针输入,则根据光标点击的位置反算step数量级,实现"点到哪一位就编辑哪一位"。

这一设计在仓库的 lv_demo_keypad_encoder.c 中有直接印证:键鼠/旋钮演示将 Spinbox 与其他控件一起放入控件组,验证其旋钮操作路径;lv_demo_stress.c 也在压力测试中通过set_digit_format(6, 3)、set_step(10)、连续increment等组合验证其高频刷新稳定性。

六、MicroPython 版本

虽然index.rst标注 "No examples yet",但示例目录实际提供了 lv_ex_spinbox_1.py,API 与 C 版一一对应:

def event_handler(obj, event): if event == lv.EVENT.VALUE_CHANGED: print("Value: %d" % obj.get_value()) elif event == lv.EVENT.CLICKED: # For simple test: Click the spinbox to increment its value obj.increment() spinbox = lv.spinbox(lv.scr_act()) spinbox.set_digit_format(5, 3) spinbox.step_prev() spinbox.set_width(100) spinbox.align(None, lv.ALIGN.CENTER, 0, 0) spinbox.set_event_cb(event_handler)

值得注意的两点差异:Python 版采用set_digit_format(5, 3)(3 位整数 + 2 位小数),并在事件回调中监听VALUE_CHANGED(值变化)与CLICKED(单击时直接调用obj.increment()做演示),展示了"点击 Spinbox 本体即可加值"与"读取回调值"两种典型用法。

七、在 HoloCubic 项目中的应用思路

HoloCubic 固件(2.Firmware/HoloCubic-fw)的 GUI 基于同版本 LVGL 构建,从源码结构看,其界面代码集中在gui_guider.c、setup_scr_home.c、setup_scr_scenes.c等文件,采用 GuiGuider 生成的屏幕管理方式。Spinbox 非常适合用于这类桌面站的参数设置场景,例如:

  • 时钟/闹钟设置:用 Spinbox 分别设置小时、分钟的数值位;
  • 网络与系统参数:设置亮度、音量、刷新间隔等需要精确数值的配置项;
  • 配合旋转编码器:HoloCubic 这类带实体按键/旋钮的设备可借助本文 5.4 节的键盘控制路径,实现"旋钮选择位、按键增减"的完整调节体验。

具体集成方式:在目标屏幕的lv_*_gui_create流程中调用lv_ex_spinbox_1()或按同样模式新建 Spinbox,并在事件回调(LV_EVENT_VALUE_CHANGED)中读取lv_spinbox_get_value()后换算为实际参数写入应用逻辑。

八、相关资源汇总

  • 示例文档:2.Firmware/Libraries/lvgl/src/lv_examples/src/lv_ex_widgets/lv_ex_spinbox/index.rst
  • 示例源码(C / Python):lv_ex_spinbox_1.c、lv_ex_spinbox_1.py
  • 控件头文件与实现:lv_spinbox.h、lv_spinbox.c
  • 启用开关:lv_conf.h
  • 主题样式:lv_theme.c、lv_theme_material.c
  • 组合应用示例:lv_demo_keypad_encoder.c、lv_demo_stress.c

至此,从示例文档出发,我们已经完整覆盖了 Spinbox 的启用、创建、配置、交互到底层格式化与输入处理的全部环节,可以直接在 HoloCubic 固件或任意 LVGL 工程中复用这套模式实现数值输入界面。

  • 嵌入式
  • 物联网
  • 智能硬件
  • 嵌入式GUI
  • 硬件开发

【免费下载链接】HoloCubic

带网络功能的伪全息透明显示桌面站

项目地址:https://gitcode.com/gh_mirrors/ho/HoloCubic
点击查看免费下载

相关推荐

上一篇:genshin-fps-unlock:突破原神帧率限制的开源工具使用指南
下一篇:开源工具mimotion:2025革新方案实现运动数据同步

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 22:14:17

强化学习真机部署:跨越仿真与现实的认知鸿沟

1. 项目概述&#xff1a;当强化学习走出仿真器&#xff0c;机器人第一次“睁眼”时在想什么&#xff1f;“强化学习真机部署&#xff1a;机器人在仿真里&#xff0c;究竟学会了什么&#xff1f;”——这句话不是设问&#xff0c;是我在去年带一个四足机器人项目时&#xff0c;连…

作者头像 李华
网站建设 2026/10/19 10:38:36

高速扫描振镜驱动原理图设计五大硬约束与实测验证

简介&#xff1a;本资源是一份面向电机驱动工程师、光学扫描系统开发者及嵌入式硬件设计学习者的高速扫描振镜驱动电路原理图&#xff0c;聚焦于激光打标、精密投影等场景下的高动态响应控制需求。原理图完整呈现了基于PID闭环的位置伺服架构&#xff0c;涵盖差分指令输入、编码…

作者头像 李华
网站建设 2026/10/18 7:47:18

康明斯发动机CAN诊断协议实战:从J1939/UDS到可运行脚本

简介&#xff1a;本资源是康明斯Quantum系列发动机专用的诊断与CAN通信技术指南&#xff0c;面向整车厂&#xff08;OEM&#xff09;、工程机械及发电设备集成工程师&#xff0c;解决发动机嵌入式系统对接、故障诊断逻辑理解与J1587/J1939协议落地实施等核心问题。文档为单文件…

作者头像 李华
网站建设 2026/10/19 1:35:55

基于Django的研招管理平台:从需求拆解到部署的全过程复盘

每年9月到次年6月&#xff0c;研招办都是学校里最忙的部门之一。为了把校园研究生招生研招网平台做好&#xff0c;我从Python技术栈入手&#xff0c;先后对比了Django和Flask两套框架&#xff0c;最终用Django完成了一套可稳定运行的招生管理平台。这篇文章就是对这个项目完整过…

作者头像 李华
网站建设 2026/10/18 13:03:30

回放学习的局限性:为什么AI在复杂游戏规则下会卡壳

1. 项目概述&#xff1a;当AI智能体开始“打游戏学做人”最近在几个技术社区刷到一个挺有意思的说法&#xff1a;“清华AAArena里&#xff0c;AI智能体正靠回放学游戏”。标题里那个“Pacman登顶但复杂规则卡壳”&#xff0c;听着像段子&#xff0c;细琢磨却戳中了当前AI智能体…

作者头像 李华