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

相关推荐
小小筱筱10 分钟前
LabVIEW笔记:解决周立功CAN卡驱动缺失导致的启动报错问题
笔记·labview
workflower27 分钟前
案例 :某交通厅基于AI技术的智能安全运营实践
网络·人工智能·安全·设计模式·机器人
Wang's Blog28 分钟前
PostgreSQL笔记4: 市场地位、生态全景与行业应用实践
数据库·笔记·postgresql
RainCity43 分钟前
Java Swing 自定义组件库分享(十六)
java·笔记·后端
蒸蒸yyyyzwd2 小时前
cpp选手秋招准备 学习笔记day7 webserver
笔记·学习
Chen—LSN4 小时前
C语言——数据在内存中的存储
c语言·开发语言·经验分享·笔记
bitbrowser15 小时前
giffgaff突然停用?先分清闲置停用和长期境外断开
笔记
九硕智慧建筑一体化厂家15 小时前
数字化管控落地,直流照明构筑安全照明体系
运维·人工智能·笔记·安全·智慧城市
AI云海15 小时前
天幕红尘笔记
笔记
青山是哪个青山18 小时前
LangChain 学习笔记(三):LangSmith 调试与监控
笔记·学习·langchain