嵌入式:简单的UI框架

news2024/12/23 11:01:40

1:UI框架简介

        除了服务框架外,我们还需要对外显示UI,所以我们就需要一个UI的框架,跟服务框架一样,不用这个UI框架我们也是可以实现,但是这样每个人写的UI都会有差异,需要的事件,数据都是独立的,重复的代码也多。但是有UI框架之后就比较方便;例如每个界面都是识别到按键(以手表为例子)有框架直接 case:SINGLE_CLICK,即可,需要什么事件叫框架帮忙统一添加处理即可。除了负责事件的分发、还有就是UI界面的切换、动效等。

1.1:UI框架简流程

图1.1.1    

        如图1.1.1所示UI框架就是负责分发UI的事件,然后负责显示,UI直接的切换动画。UI的事件分发跟服务框架的设计是一样的、UI的显示需要底层去实现有用mipi、qspi、spi的接口的显示器。动画的切换的话需要自己进行代码逻辑的编写,还得引入第三方的算法如动画曲线(贝塞尔曲线)。

2:代码

2.1 窗口的数据结构:

typedef struct _gui_win_t {
#if GUI_WIN_USE_GRAPHIC_ENGINE == GUI_WIN_GRAPHIC_ENGINE_GUIX
    GX_WIDGET *win;               /** window handle */
    GX_STUDIO_WIDGET *studio_win; /** studio window handle */
    GUI_WIN_REG_TYPE_E reg_type;  /** registration type */
#endif
    GUI_WIN_PAGE_PRIO_E win_prio; /** page priority */
    char *win_name;               /** window name */
    uint8_t win_type;             /** window type */
    uint8_t notify_disp;          /** notify display type */
    /** window state */
    uint32_t disp_sec;            /** display time */
    uint32_t idel_exit_sec;       /** idle exit time */

    uint32_t (*init)(struct _gui_win_t *win);                      /** window init */
    uint32_t (*deinit)(struct _gui_win_t *win);                    /** window deinit */
    uint32_t (*event)(struct _gui_win_t *win, gui_event_t *event); /** window event handler */
} gui_win_t;

        这个GUI_WIN_USE_GRAPHIC_ENGINE宏控制着使用着不同的GUI平台。重点就是窗口的init、deinit、event。这个控制了窗口的初始化、反初始化,还有就是给窗口发送的事件函数处理。  

        _gui_win_t  类型根据不同的GUI平台,是不一样的,可自行进行构造。

2.2 gui 平台初始化

void gui_win_guix_init(void)
{
    /* Create all windows */
    for (int i = 0; i < GUI_WIN_ID_MAX; i++) {
        if (gui_win_table[i].win_name == NULL) {
            continue;
        }
        if (gui_win_table[i].reg_type == GUI_WIN_REG_SOFT_AUTO_REG) {
            UINT status = gx_studio_named_widget_create(gui_win_table[i].win_name, GX_NULL, GX_NULL);
            if (status != GX_SUCCESS) {
                log_e("Create window %s failed(%d)", gui_win_table[i].win_name, status);
                return;
            }
        } else if (gui_win_table[i].reg_type == GUI_WIN_REG_SOFT_MANUAL_REG) {
            GX_WIDGET *studio_win = gx_studio_widget_create((GX_BYTE *)gui_win_table[i].win, gui_win_table[i].studio_win, GX_NULL);
            if (studio_win == GX_NULL) {
                log_e("Create window %s failed(%d)", gui_win_table[i].win_name, status);
                return;
            }
        }
    }
    /** GUI animation init */
    gui_win_guix_anim_init();
}

        上述的初始化就是根据不同的UI平台进行创建的,这个可根据实际的来进行。

2.3 窗口配置

const gui_win_t gui_win_table[GUI_WIN_ID_MAX] = {
    [GUI_WIN_ID_WELCOME] = {
        .win = (GX_WIDGET*)&welcome_screen,
        .win_name = "welcome_screen",
        .win_type = GUI_WIN_TYPE_APP,
        .notify_disp = GUI_WIN_NOTIFY_DISP_NONE,
        .disp_sec = GUI_WIN_DISP_SEC_KEEP_BRIGHT,
        .idel_exit_sec = GUI_WIN_IDEL_EXIT_SEC_KEEP_NOT_QUIT,
        .init = gui_win_welcome_init,
        .deinit = gui_win_welcome_deinit,
        .event =  gui_win_welcome_event,
    },
};

        .win:根据不同的GUI平台,类型都是不一样的,但是都是可以当做一个obj的对象。

        .init = gui_win_welcome_init

        .deinit = gui_win_welcome_deinit

        .event = gui_win_welcome_event

        上述的这个三个配置是建议都要配置的,不要填NULL,如果选用的GUI平台自带了的话,那就可以不用写,没有的话就要填写。

        .win_name

        .win_type

        .notify_disp

        .disp_sec

        .idel_exit_sec

        上述这几个参数可进行选配的不是必选的。

        除了上述的这几个配置,还可以引入APP的概念,一个功能有可能会有几个界面,当退出一个功能的时候,只需要发起退出某个“APP”就可以把相关联的win id都退了。

        窗口的注册还可以写成一个宏,在自己的win screen 里面进行注册,窗口就不需要修改同一个文件,就像rtos创建任务一样。

2.4 进入窗口 

uint32_t gui_win_enter(GUI_WIN_ID win_id, GUI_WIN_ANIM_TYPE_E anim)
{
    GUI_WIN_ID cur_id = gui_win_get_active_win_id();
    GUI_WIN_TYPE_E cur_win_type = gui_win_table[cur_id].win_type;

    if (win_id >= GUI_WIN_ID_MAX) {
        log_e("win id is invalid");
        return GUI_WIN_RET_PARAM_ERR;
    }
    if (cur_id == win_id) {
        log_w("win %d is already active", win_id);
        return GUI_WIN_RET_OK;
    }

    log_d("cur win prio: %d, win prio: %d", gui_win_table[cur_id].win_prio,
          gui_win_table[win_id].win_prio);
    /** Check the window priority */
    if (g_win_manager.stack_depth >= 1 &&
        gui_win_table[cur_id].win_prio > gui_win_table[win_id].win_prio) {
        if (gui_win_table[win_id].init) {
            gui_win_table[win_id].init(gui_win_id_get_win(win_id));
        }
        /***********************Add your own code*****************************/
            ...
    } else {
        /** Enter the page to call the init function of the page */
        if (gui_win_table[win_id].init) {
            gui_win_table[win_id].init(gui_win_id_get_win(win_id));
        }
        /***********************Add your own code*****************************/
            ...
#if GUI_WIN_USE_GRAPHIC_ENGINE == GUI_WIN_GRAPHIC_ENGINE_GUIX
    /** Add a window to the window stack list */
#endif
    }
    return GUI_WIN_RET_OK;
}

2.5 退出窗口  

uint32_t gui_win_exit(GUI_WIN_ID win_id, GUI_WIN_ANIM_TYPE_E anim)
{
    if (win_id >= GUI_WIN_ID_MAX) {
        log_e("win id is invalid");
        return GUI_WIN_RET_PARAM_ERR;
    }
    /***********************Add your own code*****************************/
    ...
#if GUI_WIN_USE_GRAPHIC_ENGINE == GUI_WIN_GRAPHIC_ENGINE_GUIX
    if (g_win_manager.stack_depth == 0) {
        log_w("stack depth is 0");
        return GUI_WIN_RET_PARAM_ERR;
    }
    /** Remove a window from the window stack list */
    gui_list_stack_remove_win(win_id);
    /** Exit the page and call the deinit function of the page */
    if (gui_win_table[win_id].deinit) {
        gui_win_table[win_id].deinit(gui_win_id_get_win(win_id));
    }
#endif
    return GUI_WIN_RET_OK;
}

3:结论

        上述的只是提供了一个简单的窗口管理思路,统一管理系统事件的发送到顶层的窗口、进入退出的函数处理。这个思路跟另一篇文章简单的server框架差不多。

        UI框架的还有一个重要的核心就是使用的UI系统的适配(lvgl等)把这个系统接入进行,并实现窗口切换的动画(覆盖、移动、跳转、回弹等)。

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

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

相关文章

牛客JS题(二十)判断斐波那契数组

注释很详细&#xff0c;直接上代码 涉及知识点&#xff1a; 循环判断斐波那契数列组递归判断斐波那契数列组合法性判断 题干&#xff1a; 我的答案 <!DOCTYPE html> <html><head><meta charset"utf-8" /></head><body><scrip…

嵌入式数据库 sqlite3

数据库文件与普通文件区别: 1.普通文件对数据管理(增删改查)效率低 2.数据库对数据管理效率高,使用方便 常用数据库: 1.关系型数据库 将复杂的数据结构简化为二维表格形式 大型:Oracle、DB2 中型:MySql、SQLServer 小型:Sqlite …

c# .net core项目角色授权机制

前言 角色授权机制是确保应用程序安全性的重要组成部分,它允许开发者根据用户的角色来限制对应用程序中不同资源的访问。 基本概念: 角色授权基于用户角色的访问控制,即根据用户所属的角色来决定其能够访问的资源或执行的操作。在.NET Core中,这通常与身份认证(Authent…

怎么配置一个axios来拦截前后端请求

首先创建一个axios.js文件 导入我们所需要的依赖 import axios from "axios"; import Element from element-ui import router from "./router"; 设置请求头和它的类型和地址 注意先注释这个url,还没有解决跨域问题,不然会出现跨域 // axios.defaults.…

Python Sklearn库SVM算法应用

SVM 是一种有监督学习分类算法&#xff0c;输入值为样本特征值向量和其对应的类别标签&#xff0c;输出具有预测分类功能的模型&#xff0c;当给该模型喂入特征值时&#xff0c;该模型可以它对应的类别标签&#xff0c;从而实现分类。 Sklearn库SVM算法 下面我看一下 Python …

CSS学习 - 选择器

基础选择器 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 类型选择器&…

牛逼,两百行Python代码带你打造一款《天天酷跑》游戏!(附源码)

《天天酷跑》是一款广受欢迎的跑酷类手机游戏&#xff0c;玩家需要控制角色在赛道上奔跑&#xff0c;躲避障碍物&#xff0c;收集金币和道具&#xff0c;以获取高分。虽然完全复现这款游戏的复杂度和图形效果在简单的Python环境中难以实现&#xff08;特别是游戏图形和动画&…

市电220V

概念 市电 220V 是指在中国及许多其他国家使用的标准交流电压,该值是电压的有效值(RMS值,Root Mean Square)。有效值是交流电压或电流的一个测量方式,它表示在一个周期内,交流电的平方平均值等于直流电压(或电流)的值。 有效值在交流电中具有特殊意义,因为交流电的瞬…

华大基因守护新生健康,基因检测助力新生儿疾病筛查

此前&#xff0c;《中国出生缺陷防治报告》预估我国出生缺陷发生率在5.6%左右&#xff0c;无创产前基因检测技术&#xff08;NIPT&#xff09;等先进产前筛查手段&#xff0c;在我国历经十多年的发展历史&#xff0c;华大基因作为行业引领者&#xff0c;深耕基因检测领域&#…

JavaEE 初阶(11)——多线程9之“阻塞队列”

目录 一. 什么是“阻塞队列” 二. 生产者消费者模型 2.1 概念 2.2 组件 2.3 实际应用 2.4 优点 a. 实现“解耦合” b. 流量控制——“削峰填谷” 2.5 代价 a. 更多的机器 b. 通信时间延长 三. 阻塞队列的实现 3.1 简述 3.2 ArrayBlockingQueue的使用 3.3 实现…

数据建模标准-基于事实建模

前情提要 数据模型定义 DAMA数据治理体系中将数据模型定义为一种文档形式&#xff0c;数据模型是用来将数据需求从业务传递到IT,以及在IT内部从分析师、建模师和架构师到数据库设计人员和开发人员的主要媒介&#xff1b; 作用 记录数据需求和建模过程中产生的数据定义&…

dctcp 比 reno,cubic 好在哪

dctcp 相比标准 aimd 如 reno&#xff0c;cubic 到底好在哪&#xff0c;理论上讲 dctcp 本质上也是 aimd 算法&#xff0c;但它的 cwnd 根据 mark rate 来实时缩放&#xff0c;而标准 reno/cubic 则一致缩放 β 0.5(reno) or β 0.3(cubic)&#xff0c;直观上看 dctcp 是连续…

PostgreSQL数据库内核(一):增加系统表pg_test_catalog

目录 编译环境准备 gdb调试 CLion配置 增加系统表pg_test_catalog 编译环境准备 使用PostgreSQL14.5源码版本编译&#xff0c;操作系统CentOS&#xff0c;本地windos系统CLion代码工具&#xff0c;首先下载pg源码&#xff0c;上传CentOS系统&#xff1a; more /etc/os-rel…

要 set 还是 map? 我全要

引子&#xff1a; 时隔多日&#xff0c;我又回来啦&#xff0c;接上回&#xff0c;我们讲到set的一小部分&#xff0c;我们今天来讲详细讲set与map&#xff0c;满满干货启动&#xff01;根据应用场景的不同&#xff0c;STL总共实现了两种不同结构的管理式容器&#xff1a;树型…

[240803] Prompt Fuzzer 新版本发布 | Windows 会在更新时进行时间调整以减少碳排放

目录 Prompt Fuzzer 新版本发布&#xff1a;更强大、更灵活的 GenAI 应用安全评估工具Windows 会在更新时进行时间调整以减少碳排放 Prompt Fuzzer 新版本发布&#xff1a;更强大、更灵活的 GenAI 应用安全评估工具 Prompt Security 发布了新版 Prompt Fuzzer&#xff0c;这是…

CSS+js:顶部导航栏背景滚动渐变、顶部背景滚动渐变

一、效果图 图1 图2 图3 二、gradual.html代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>顶部导航栏渐变和顶部背景渐变</title></head><body><div class"content-root" id&quo…

Linux PSCI框架

Linux PSCI框架 概述 参考链接&#xff1a; 简单讲解Linux PSCI框架-Linxu内核栈 概述 PSCI &#xff08;Power State Coordination Interface&#xff09; 是ARM定义的电源管理接口规范&#xff0c;由firm来实现。Linux系统通过smc/hvc指令&#xff08;设备树可查看是那种&a…

5.7软件质量和软件度量

软件质量和软件度量 软件质量软件质量特性ISO/EC9126软件质量模型练习题Mc Call质量模型 软件质量保证软件评审软件容错技术结构冗余信息冗余时间元余冗余附加技术 软件度量练习题 软件质量 软件质量&#xff1a;是指反映软件系统或软件产品满足规定或隐含需求的能力的特征和特…

代码随想录算法训练营day32 | 509. 斐波那契数 、70. 爬楼梯 、746. 使用最小花费爬楼梯

碎碎念&#xff1a;开始动态规划了&#xff01;加油&#xff01; 参考&#xff1a;代码随想录 动态规划理论基础 动态规划常见类型&#xff1a; 动规基础类题目背包问题打家劫舍股票问题子序列问题 解决动态规划问题应该要思考清楚的&#xff1a; 动态规划五部曲&#xff1…

使用 continue 自定义 AI 编程环境

一直在使用github 的 copilot 来编程&#xff0c;确实好用&#xff0c;对编码效率有很大提升。 但是站在公司角度&#xff0c;因为它只能对接公网&#xff08;有代码安全问题&#xff09;。另外&#xff0c;它的扩展能力也不强&#xff0c;无法适配公司特定领域的知识库&#x…