如何在LVGL中实现可正确递增的时间刻度X轴?
如何在LVGL中实现可正确递增的时间刻度X轴?
嗨,我来帮你解决这个问题!你遇到的情况应该是初始化X轴刻度时只固定了一个时间值,没有根据每个刻度的位置计算对应的递增时间。下面是具体的解决思路和代码示例,都是基于最新LVGL master分支的:
核心思路
LVGL的轴刻度标签支持自定义格式化回调函数,我们可以利用这个回调,根据每个刻度的数值偏移量来计算对应的时间,而不是用固定的初始时间。这样每个刻度就能显示递增的HH:MM:SS了。
具体实现步骤
定义起始时间基准
先确定时间轴的起始点,可以用系统时间,也可以用LVGL内部的tick值(更适合嵌入式环境,不依赖系统时间)。这里两种方式都给你示例:用系统时间的方式:
static time_t start_time; // 记录时间轴的起始时间用LVGL内部tick的方式(推荐嵌入式场景):
static uint32_t start_tick; // 记录时间轴起始时的LVGL tick值(单位ms)
编写自定义刻度标签格式化函数
这个函数会被LVGL调用,传入每个刻度的数值(比如0、1、2...对应秒数偏移),我们把这个偏移量转换成对应的HH:MM:SS格式:系统时间版本:
static char * time_axis_label_formatter(lv_obj_t * axis, int32_t value) { static char buf[10]; // 静态缓冲区,用于返回格式化后的字符串 // value是当前刻度对应的秒数偏移,计算该刻度的实际时间 time_t tick_time = start_time + value; struct tm * tm_info = localtime(&tick_time); // 格式化为HH:MM:SS strftime(buf, sizeof(buf), "%H:%M:%S", tm_info); return buf; }LVGL tick版本:
static char * time_axis_label_formatter(lv_obj_t * axis, int32_t value) { static char buf[10]; // value是秒数偏移,转换成LVGL tick的ms值 uint32_t total_ms = start_tick + value * 1000; uint32_t total_sec = total_ms / 1000; // 拆分时、分、秒 uint8_t h = total_sec / 3600; uint8_t m = (total_sec % 3600) / 60; uint8_t s = total_sec % 60; // 格式化输出 snprintf(buf, sizeof(buf), "%02d:%02d:%02d", h, m, s); return buf; }
初始化时间轴并绑定格式化函数
在创建X轴对象后,把上面的回调函数绑定到轴上,同时设置刻度范围和间隔:// 假设你的轴对象是axis_x(从图表中获取或直接创建) lv_obj_t * axis_x = lv_chart_get_axis(chart, LV_CHART_AXIS_PRIMARY_X); // 绑定自定义格式化函数 lv_axis_set_label_formatter_cb(axis_x, time_axis_label_formatter); // 设置刻度范围:比如显示0到60秒(1分钟的时间轴) lv_axis_set_range(axis_x, 0, 60); // 设置刻度样式:每1秒一个小刻度,每5秒一个带标签的大刻度 lv_axis_set_tick_length(axis_x, 5, 10); // 小刻度长度5px,大刻度10px lv_axis_set_major_tick_count(axis_x, 13); // 0、5、10...60,共13个大刻度 lv_axis_set_minor_tick_count(axis_x, 4); // 每个大刻度间4个小刻度如果需要实时推进时间轴(可选)
如果你的时间轴是动态滚动的(比如实时显示流逝的时间),可以用LVGL定时器每秒更新起始时间并刷新轴:static void time_axis_update_timer(lv_timer_t * timer) { lv_obj_t * axis_x = timer->user_data; // 每秒推进1秒 start_time += 1; // 系统时间版本 // start_tick += 1000; // LVGL tick版本 // 刷新轴,让标签重新计算 lv_obj_invalidate(axis_x); } // 在初始化时创建定时器(间隔1000ms,即1秒) lv_timer_create(time_axis_update_timer, 1000, axis_x);
一些优化建议
- 如果刻度比较密集,HH:MM:SS可能会挤在一起,可以调整标签显示逻辑:比如只给每5秒的大刻度显示完整时间,小刻度只显示秒数。
- 静态缓冲区在单线程LVGL应用中没问题,如果是多线程场景,可以改用线程本地存储或者动态分配(记得及时释放内存避免泄漏)。
- 若不需要时区转换,系统时间版本可以用
gmtime代替localtime,得到UTC时间。
备注:内容来源于stack exchange,提问作者triz
相关产品推荐
相关产品推荐

