lvgl 页面管理器

lv_scr_mgr

lvgl 界面管理器

适配 lvgl 8.3

  • 降低界面之间的耦合
  • 使用较小的内存,界面切换后会自动释放内存
  • 内存泄漏检测
    请添加图片描述

使用方法

  1. 在lv_scr_mgr_port.h 中创建一个枚举,用于界面ID
  2. 为每个界面创建一个页面管理器句柄
  3. 将界面句柄添加到 lv_scr_mgr_port.c 数组中
  4. 在 lv_init() 后,对页面管理器进行初始化 lv_scr_mgr_init(NULL);
  5. 使用 lv_scr_mgr_switch 设置初始根界面
  6. 使用 lv_scr_mgr_push lv_scr_mgr_pop 对界面进行操作

git地址

git地址
gitee

/*********************************CopyRight  ************************************* @file    lv_scr_mgr.c* @author  不咸不要钱* @date    2023-10-11 13:4:36* @brief   &#&*          *******************************************************************************//* Includes ------------------------------------------------------------------*/
#include "lvgl.h"
#include "lv_scr_mgr.h"
#if !LV_SCR_MGR_REG_ENABLE
#include "lv_scr_mgr_port.c"
#endiftypedef struct
{uint32_t               scr_cnt; void*                  param;lv_scr_mgr_handle_t    **handles;
#if LV_SCR_MGR_PRINTF_MEMuint32_t               *max_mem;
#endif
}scr_mgr_list_handle_t;static scr_mgr_list_handle_t     mgr_list;
static lv_scr_mgr_stack_node_t*      mgr_stack_top = NULL;
static lv_scr_mgr_stack_node_t*      mgr_stack_root = NULL;static lv_scr_mgr_handle_t* find_handle_by_id(uint32_t id)
{for (int i = 0; i < mgr_list.scr_cnt; i++){if (mgr_list.handles[i]->scr_id == id){return mgr_list.handles[i];}}return NULL;
}
#if LV_SCR_MGR_PRINTF_MEM
static uint32_t* find_mem_addr_by_id(uint32_t id)
{for (int i = 0; i < mgr_list.scr_cnt; i++){if (mgr_list.handles[i]->scr_id == id){return &mgr_list.max_mem[i];}}return NULL;
}static void mem_max_printf(uint32_t id)
{static uint32_t mem_max = 0;lv_mem_monitor_t mon;lv_mem_monitor(&mon);if (mon.total_size - mon.free_size > mem_max){mem_max = mon.total_size - mon.free_size;LV_LOG_USER("used: %d (%d %%), frag: %d %%, biggest free: %d\n", mem_max,mon.used_pct,mon.frag_pct,(int)mon.free_biggest_size);}/* 当前界面最大使用内存 */uint32_t* page_max_mem = find_mem_addr_by_id(id);if (mon.total_size - mon.free_size > *page_max_mem){*page_max_mem = mon.total_size - mon.free_size;LV_LOG_USER("page id %d, used: %d (%d %%), frag: %d %%, biggest free: %d\n", id, *page_max_mem,mon.used_pct,mon.frag_pct,(int)mon.free_biggest_size);}
}static void anim_mem_max_printf(lv_event_t* e)
{lv_event_code_t event_code = lv_event_get_code(e);if (event_code == LV_EVENT_SCREEN_LOADED){mem_max_printf((uint32_t)lv_event_get_user_data(e));}
}
#endifstatic void scr_mgr_stack_free(void)
{lv_scr_mgr_stack_node_t* stack_node = NULL;/* 释放界面栈 */while (NULL != mgr_stack_top){stack_node = mgr_stack_top->prev;if(mgr_stack_top->handle->scr_destroy)mgr_stack_top->handle->scr_destroy();lv_mem_free((void*)mgr_stack_top);mgr_stack_top = stack_node;}mgr_stack_root = NULL;
}/*** @brief 入栈* @param tag 要入栈的句柄* @return 栈顶句柄
*/
static lv_scr_mgr_stack_node_t* scr_mgr_stack_push(lv_scr_mgr_handle_t* tag)
{lv_scr_mgr_stack_node_t* stack_node = NULL;stack_node = lv_mem_alloc(sizeof(lv_scr_mgr_stack_node_t));LV_ASSERT_MALLOC(stack_node);stack_node->handle = tag;stack_node->next = NULL;if (stack_node->handle->scr_first_create){stack_node->handle->scr_first_create();}if (tag->scr_create){stack_node->scr = tag->scr_create(stack_node->handle->scr_id, mgr_list.param);}else{LV_LOG_ERROR("no create fun!");}if (NULL == mgr_stack_top){stack_node->prev = NULL;mgr_stack_root = stack_node;}else{stack_node->prev = mgr_stack_top;mgr_stack_top->next = stack_node;}mgr_stack_top = stack_node;return stack_node;
}static int32_t scr_mgr_stack_pop(int32_t n)
{lv_scr_mgr_stack_node_t* stack_node = NULL;int32_t i = n;if ((NULL == mgr_stack_top) || (NULL == mgr_stack_top->prev)){return 0;}while (i){if ((NULL == mgr_stack_top) || (NULL == mgr_stack_top->prev)){break;}stack_node = mgr_stack_top->prev;if (mgr_stack_top->handle->scr_destroy){mgr_stack_top->handle->scr_destroy();}lv_mem_free((void*)mgr_stack_top);mgr_stack_top = stack_node;i--;}if (NULL != mgr_stack_top->handle->scr_create){mgr_stack_top->scr = mgr_stack_top->handle->scr_create(mgr_stack_top->handle->scr_id, mgr_list.param);}else{LV_LOG_ERROR("no create fun!");}if (i){LV_LOG_WARN("stack pop %d, but stack is %d", n, n-i);}return n - i;
}/*** @brief 切换界面* @param cur_scr 当前界面* @param stack_node 目标界面句柄* @param anim 切换界面动画开关*             关闭界面切换动画,切换界面时会先创建一个新的空界面,切换到空界面后,*             删除之前的界面,然后再创建切换到新界面,最后再删除中间界面。会节省内存。*             关闭界面切换动画,切换界面时直接创建新界面,然后再用动画切换到新界面。** @return true
*/
bool scr_mgr_switch(lv_obj_t* cur_scr, lv_scr_mgr_stack_node_t* stack_node, bool anim)
{lv_scr_load_anim_t load_anim = LV_SCR_MGR_LOAD_ANIM_DEFAULT;lv_obj_t* tmp_scr = NULL;if (anim){if ((stack_node->handle->anim_type != LV_SCR_LOAD_ANIM_NONE) && (LV_SCR_LOAD_ANIM_OUT_BOTTOM >= stack_node->handle->anim_type)){load_anim = stack_node->handle->anim_type;}#if LV_SCR_MGR_PRINTF_MEMlv_obj_add_event_cb(stack_node->scr, anim_mem_max_printf, LV_EVENT_SCREEN_LOADED, stack_node->handle->scr_id);
#endiflv_scr_load_anim(stack_node->scr, load_anim, LV_SCR_MGR_LOAD_ANIM_TIME, LV_SCR_MGR_LOAD_ANIM_DELAY, true);}else{if (NULL != cur_scr){tmp_scr = lv_obj_create(NULL);lv_scr_load(tmp_scr);lv_obj_del(cur_scr);cur_scr = NULL;}lv_scr_load(stack_node->scr);#if LV_SCR_MGR_PRINTF_MEMmem_max_printf(stack_node->handle->scr_id);
#endifif (NULL != tmp_scr){lv_obj_del(tmp_scr);}}return true;
}/*** @brief 初始化界面管理器* @param param 创建界面时的参数* @return 
*/
bool lv_scr_mgr_init(void* param)
{mgr_list.param = param;
#if LV_SCR_MGR_REG_ENABLE#elsemgr_list.scr_cnt = sizeof(scr_mgr_handles) / sizeof(scr_mgr_handles[0]);mgr_list.handles  = scr_mgr_handles;
#endif    if (0 == mgr_list.scr_cnt){LV_LOG_ERROR("no screen!");return false;}#if LV_SCR_MGR_PRINTF_MEMmgr_list.max_mem = lv_mem_alloc(mgr_list.scr_cnt * sizeof(uint32_t*));LV_ASSERT(mgr_list.max_mem);memset(mgr_list.max_mem, 0, mgr_list.scr_cnt * sizeof(uint32_t*));
#endifreturn true;
}void lv_scr_mgr_deinit(void)
{mgr_list.param = NULL;
#if LV_SCR_MGR_PRINTF_MEMlv_mem_free(mgr_list.max_mem);
#endifscr_mgr_stack_free();
}void lv_scr_mgr_param_set(void* param)
{mgr_list.param = param;
}void* lv_scr_mgr_param_get(void)
{return mgr_list.param;
}/*** @brief 设置根界面* @param id 根界面序号* @param anim 动画开关* @return 
*/
bool lv_scr_mgr_switch(uint32_t id, bool anim)
{lv_scr_mgr_handle_t* tag_handle = find_handle_by_id(id);lv_scr_mgr_handle_t* cur_handle = NULL;lv_scr_mgr_stack_node_t* stack_node = NULL;lv_obj_t* cur_scr = NULL;if (NULL == tag_handle){LV_LOG_ERROR("no screen, id %d", id);return false;}if (NULL != mgr_stack_top){/* 栈内有界面 */cur_handle = mgr_stack_top->handle;cur_scr = mgr_stack_top->scr;}else{cur_scr = lv_scr_act();}scr_mgr_stack_free();if ((NULL == cur_handle) || (tag_handle->scr_id == cur_handle->scr_id)){/* 没有界面切换,不使用动画效果 */anim = false;}stack_node = scr_mgr_stack_push(tag_handle);return scr_mgr_switch(cur_scr, stack_node, anim);
}/*** @brief 入栈一个新的界面* @param id * @param anim * @return 
*/
bool lv_scr_mgr_push(uint32_t id, bool anim)
{lv_scr_mgr_handle_t* tag_handle = find_handle_by_id(id);lv_scr_mgr_stack_node_t* stack_node = NULL;lv_obj_t* cur_scr = NULL;if (NULL == tag_handle){LV_LOG_ERROR("no screen, id %d", id);return false;}if ((NULL == mgr_stack_top) || (NULL == mgr_stack_root)){LV_LOG_ERROR("no root screen, please use lv_scr_mgr_switch create root screen");return false;}cur_scr = mgr_stack_top->scr;stack_node = scr_mgr_stack_push(tag_handle);return scr_mgr_switch(cur_scr, stack_node, anim);
}/*** @brief 出栈n个界面* @param n 如果栈内界面没有n个,则返回根界面* @param anim * @return 
*/
bool lv_scr_mgr_popn(uint32_t n, bool anim)
{lv_obj_t* cur_scr = NULL;if ((mgr_stack_top == NULL) || (mgr_stack_top->prev == NULL)){return false;}cur_scr = mgr_stack_top->scr;scr_mgr_stack_pop(n);return scr_mgr_switch(cur_scr, mgr_stack_top, anim);
}/*** @brief 出栈一个界面* @param anim * @return 
*/
bool lv_scr_mgr_pop(bool anim)
{return lv_scr_mgr_popn(1, anim);
}/*** @brief 退回到根界面* @param anim * @return 
*/
bool lv_scr_mgr_pop_root(bool anim)
{lv_scr_mgr_stack_node_t* stack_node = NULL;lv_scr_mgr_stack_node_t* stack_top = NULL;uint32_t cnt = 0;if (NULL == mgr_stack_root || NULL == mgr_stack_top){return false;}stack_top = mgr_stack_top;while (stack_top != NULL){cnt++;stack_node = stack_top->prev;stack_top = stack_node;}return lv_scr_mgr_popn(cnt-1, anim);
}/*** @brief 获取当前界面id* @param  * @return 
*/
int32_t lv_scr_mgr_get_cur_id(void)
{if (NULL != mgr_stack_top && NULL != mgr_stack_top->handle){return mgr_stack_top->handle->scr_id;}else{return -1;}
}/*** @brief 获取根界面id* @param* @return
*/
int32_t lv_scr_mgr_get_root_id(void)
{if (NULL != mgr_stack_root && NULL != mgr_stack_root->handle){return mgr_stack_root->handle->scr_id;}else{return -1;}
}
/************************ (C) COPYRIGHT ***********END OF FILE*****************/
/*********************************CopyRight  ************************************* @file    lv_scr_mgr.h* @author  不咸不要钱* @date    2023-10-11 9:31:49* @brief   &#&*          *******************************************************************************/
#ifndef _LV_SCR_MGR_H_
#define _LV_SCR_MGR_H_/* Includes ------------------------------------------------------------------*/
#include "stdint.h"
#include "lvgl.h"#ifdef __cplusplus
extern "C" {
#endif/*!<  界面切换动画默认值*/
#define LV_SCR_MGR_LOAD_ANIM_DEFAULT   LV_SCR_LOAD_ANIM_MOVE_LEFT
#define LV_SCR_MGR_LOAD_ANIM_TIME      500
#define LV_SCR_MGR_LOAD_ANIM_DELAY     0/*!< 内存泄漏检测 */
#define LV_SCR_MGR_PRINTF_MEM          1   #define LV_SCR_MGR_REG_ENABLE          0#if LV_SCR_MGR_REG_ENABLE#else#endiftypedef struct
{uint32_t scr_id;                       /*!< id */lv_scr_load_anim_t      anim_type;     /*!< 切换动画类型 如果为空,则使用 LV_SCR_MGR_LOAD_ANIM_DEFAULT */void (*scr_first_create)(void);        /*!< lv_scr_mgr_switch  lv_scr_mgr_push 函数会调用该创建函数 pop则不会调用 可以方便实现pop记住焦点 而push使用默认焦点 */lv_obj_t* (*scr_create) (const uint32_t id, void* param); /*!< 创建界面,创建界面时不要使用 lv_scr_mgr_xxx 函数 */void (*scr_destroy)(void);             /*!< 删除界面的回调函数,一般用于删除如 lv_timer 等不会随界面自动删除的资源 */
}lv_scr_mgr_handle_t;typedef struct _lv_scr_mgr_stack_node_t
{lv_scr_mgr_handle_t* handle;lv_obj_t* scr;struct _lv_scr_mgr_stack_node_t* prev;struct _lv_scr_mgr_stack_node_t* next;
}lv_scr_mgr_stack_node_t;bool lv_scr_mgr_init(void* param);
void lv_scr_mgr_deinit(void);
void lv_scr_mgr_param_set(void* param);
void* lv_scr_mgr_param_get(void);bool lv_scr_mgr_switch(uint32_t id, bool anim);
bool lv_scr_mgr_push(uint32_t id, bool anim);
bool lv_scr_mgr_popn(uint32_t n, bool anim);
bool lv_scr_mgr_pop(bool anim);
bool lv_scr_mgr_pop_root(bool anim);
int32_t lv_scr_mgr_get_cur_id(void);
int32_t lv_scr_mgr_get_root_id(void);
#ifdef __cplusplus
}
#endif#endif /* _LV_SCR_MGR_H_ *//************************ (C) COPYRIGHT *****END OF FILE*****************/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/108032.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

发电机组负载测试的必要性

发电机组负载测试是确保发电机组能够在实际运行中稳定工作的重要步骤&#xff0c;负载测试可以模拟发电机组在不同负载条件下的工作情况&#xff0c;评估其性能和稳定性。负载测试可以验证发电机组在不同负载条件下的性能表现&#xff0c;通过模拟实际使用情况评估发电机组的输…

css3自动吸附scroll-snap

我们希望可以一块一块的滚动&#xff0c;比如当前一个块滚出去了一部分并且后一个块滚进来一部分的时候&#xff0c;实现后一个块自动滚入或者前一个块回弹到初始位置这种效果&#xff0c;以前的时候用js需要写比较复杂的判断逻辑&#xff0c;后来有了一个css scroll snap这个方…

Java打印二进制

&#x1f495;"把握未定&#xff0c;宜绝迹尘嚣&#xff0c;使此心不见可欲而不乱&#xff0c;以澄悟吾静体。"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;Java打印二进制 Java中打印二进制的方法有很多&#xff0c;这里介绍三种方式 1.利用In…

CSI2与CDPHY学习

注意&#xff1a;本文是基于CSI2-V3.0 spec。 其中CPHY为 V2.0 DPHY为V2.5 本文主要在packet级别介绍CSI2与对应的CDPHY&#xff0c;需要注意的是&#xff1a; CDPHY的HS burst数据和LPDT都是以packet为单位传输数据。 其中LPDT包括Escape和ALP的LPDT 1.CSI-CPHY 1.1CPH…

传输机房的基本结构

文章目录 传输机房主要结构 传输机房主要结构 ODF &#xff08;Optical Distribution Frame&#xff09;&#xff0c;光纤配线架&#xff0c;是专为光纤通信机房设计的光纤配线设备&#xff0c;具有光缆固定和保护功能、光缆终接功能、调线功能&#xff0c;完成从设备间纤缆连…

Linux学习——进程状态

目录 一&#xff0c;进程状态 1&#xff0c;进程状态的分类 2.状态的本质 3.进程状态详解 1.运行状态 2.阻塞状态 3.挂起状态 4.Linux内核中的状态分类 一&#xff0c;进程状态 1&#xff0c;进程状态的分类 如下图&#xff1a; 在计算机中我们的状态的分类便如下图所示…

【Java实战】Mysql读写分离主从复制搭建保姆级教程

MySQL 的数据同步通常采用主从复制&#xff08;Master-Slave&#xff09;的方式。 主从复制基于二进制日志&#xff08;binlog&#xff09;。主服务器&#xff08;Master&#xff09;在 binlog 中记录数据更改&#xff0c;从服务器&#xff08;Slave&#xff09;将这些日志读取…

Git版本控制管理

Git基础_环境配置 当安装Git后首先要做的事情是设置用户名称和email地址。这是非常重要的&#xff0c;因为每次Git提交都会使用该用户信息。 设置用户信息 git config --global user.name "Bandits" git config --global user.email "gb010704163.com"查…

Java反射调用jar包实现多态

上一篇实现了反射调用jar包&#xff0c;但是没有实现多态&#xff0c;这次先给自己的jar包类抽象一个接口&#xff0c;然后实现类实现接口。最后调用放反射得到的对像转换成接口类型调用执行。 定义接口&#xff0c;指定包为ZLZJar package ZLZJar;public interface ITest {p…

FPGA中的LUT查找表工作原理。

在RAM中填入1110,后续的不同AB组合Y输出对应的值&#xff0c;实现上面逻辑表达式的功能。

计算机视觉开源代码汇总

1.【基础网络架构】Regularization of polynomial networks for image recognition 论文地址&#xff1a;https://arxiv.org/pdf/2303.13896.pdf 开源代码:https://github.com/grigorisg9gr/regularized_polynomials 2.【目标检测&#xff1a;域自适应】2PCNet: Two-Phase Cons…

京东数据分析:2023年下半年母婴市场各大细分赛道消费趋势盘点!

于今天的新生代父母而言&#xff0c;在诸多消费观念被改变的当下&#xff0c;新生父母们在育儿上更强调精细化&#xff0c;在这种情况下&#xff0c;母婴市场的消费升级已是大势所趋。不过&#xff0c;在如今收入增速整体放缓的背景下&#xff0c;各细分赛道的消费升级都出现了…

网络社区挖掘-图论部分的基本知识笔记

1 网络社区挖掘定义 网络社区挖掘是指利用数据挖掘技术和机器学习算法&#xff0c;分析社交网络、在线社区或互联网上的各种交互数据&#xff0c;以揭示其中隐藏的模式、关系和信息。这些社区可以是社交媒体平台、在线论坛、博客、微博等&#xff0c;人们在这些平台上进行交流…

众和策略:尾盘5分钟拉升意味着什么?

跟着投资者越来越重视股市改动&#xff0c;一些术语逐渐进入商场人员的词汇库中&#xff0c;例如“尾盘5分钟拉升”。这个概念在许多人眼中是听起来生疏的&#xff0c;但它实际上是股市生意中十分重要的一种现象。 简略来说&#xff0c;尾盘5分钟拉升是指股市在毕竟5分钟呈现了…

智能网关IOT 2050采集应用

SIMATIC IOT2050 是西门子公司新推出的应用于企业数字化转型的智能边缘计算和云连接网关。 它将云、公司内 IT 和生产连接在一起&#xff0c;专为直接在生产环境中获取、处理和传输数据的工业 IT 解 决方案而设计。例如&#xff0c;它可用于将生产 过程与基于云的机器和生产数据…

学习记录682@查准率与查全率真的必然负相关吗?

查准率和查全率定义 查准率与查全率真的必然负相关吗&#xff1f; 先说结论&#xff0c;两者并非绝对负相关&#xff0c;只是在统计学上表现出大概率的负相关性&#xff0c;而数学证明上无法严格证明两个的负相关性。 枚举来证明两者并非必然负相关 一组数据&#xff1a;A1、…

4.2 网际协议IP

思维导图&#xff1a; 前言&#xff1a; **笔记 4.2 - 网际协议IP** 1. **定义与重要性**&#xff1a; - 网际协议IP是TCP/IP体系中的核心协议之一。 - 它是互联网的关键标准协议。 2. **发展背景**&#xff1a; - 又被称为Kahn-Cerf协议。 - 由Robert Kahn和…

vue 拿到数据后,没有重新渲染视图,nuxt.js拿到数据后,没有重新渲染视图,强制更新视图

以下为Vue2的解决方案 一、 Vue.set&#xff08;&#xff09; 问&#xff1a;什么情况下使用&#xff1f; 答&#xff1a;如果你向响应式数据添加新的“属性”&#xff0c;理论上&#xff0c;一般情况下是没问题的&#xff0c;但是&#xff0c;如果你的级别比较深&#xff0c;又…

ts使用记录

1、安装&#xff1a;通过管理员权权限使用cmd或者终端全局安装 npm install -g typescript2、运行&#xff1a; 可以通过tsc命令运行hello.ts文件 tsc hello.ts3、通过vscode的run code插件去右键运行 1.先安装插件run code 2.全局安装ts-node&#xff0c;npm install -g ts-n…

深入浅出的介绍一下虚拟机VMware Workstation——part3(VMware快照)

虚拟机VMware使用 前言快照的原理快照的使用 前言 可以先查看之前的2篇博文&#xff0c;学习基础的虚拟机使用 深入浅出的介绍一下虚拟机VMware Workstation——part1 深入浅出的介绍一下虚拟机VMware Workstation——part2(详细安装与使用) 由于我们使用虚拟机的初衷就是用来…