嵌入式:简单的UI框架

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 窗口的数据结构:

objectivec 复制代码
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 平台初始化

objectivec 复制代码
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 窗口配置

objectivec 复制代码
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 进入窗口

objectivec 复制代码
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 退出窗口

objectivec 复制代码
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等)把这个系统接入进行,并实现窗口切换的动画(覆盖、移动、跳转、回弹等)。

相关推荐
MounRiver_Studio3 小时前
RISC-V IDE MRS2调试秘籍(三):通过栈帧可视化模块定位栈溢出、栈内存非法篡改等运行时错误
mcu·risc-v·代码调试
MounRiver_Studio4 小时前
RISC-V IDE MRS2调试秘籍(一):通过Memory内存导出对比,锁定隐性内存异常代码
mcu·调试技巧·risc-v·代码调试
饼干哥哥7 小时前
用Claude Code跑通跨境电商的5大场景,顶10个人的团队
人工智能·设计模式·正则表达式
百里香酚兰8 小时前
【python学习笔记】pyttsx3库疑似只播报一次语音
笔记·python·学习
折哥的程序人生 · 物流技术专研8 小时前
第3篇:手写促销策略引擎(满减、打折、立减)
java·设计模式·策略模式·开闭原则·编程实战·扩充系列·促销引擎
sramdram9 小时前
灵动高性能32位MCU空调解决方案
单片机·嵌入式硬件·mcu·32位mcu
chnyi6_ya10 小时前
论文阅读笔记:VideoWeaver — 面向智能体长视频生成的技能评估与进化
论文阅读·笔记·音视频
J_yyy10 小时前
基于Reactor的文件管理服务开发笔记
c++·笔记·reactor·多线程编程·muduo
折哥的程序人生 · 物流技术专研10 小时前
第3篇:手写一个饮品制作模板(附代码)
java·设计模式·行为型模式·模版方法模式·钩子方法·代码复用·编程实战
浩瀚地学11 小时前
【Java基础复习】IO流(四)
java·开发语言·经验分享·笔记·学习