一个适合MCU的分级菜单框架

框架结构体如下:

cpp 复制代码
struct ui_menu
{
    uint8_t item;                         // 当前选择的子菜单编号
    uint8_t level;                          // 菜单级别,0是最高级别,主菜单。
    struct ui_menu* parent;                 // 父菜单,即上一级菜单 
    struct ui_menu* items[UI_MENU_ITEM_MAX];//此菜单下的子菜单
    uint8_t (*on_Key_Up)(void);             // 返回值,是否是最后一个子项,可根据此返回值执行特定的操作
    uint8_t (*on_Key_Down)(void);           // 返回值,是否是最后一个子项,可根据此返回值执行特定的操作
    struct ui_menu* (*on_Key_Back)(void);   // 返回上一级菜单
    struct ui_menu* (*on_Key_OK)(uint8_t* flag);
    void (*menu_Show)(void);                // 显示逻辑在此处执行
    void (*menu_Enter)(uint8_t item);       // 进入此菜单会被调用一次
    void (*menu_Exit)(void);                // 退出此菜单会被调用一次
};

菜单的链接实现

cpp 复制代码
/*
 * 连接菜单
 * @param in:parent:父菜单,为空则为顶级菜单
 * @param in:item:父菜单下的一个菜单项,不能为空
 * @param in:itemIndex:本菜单功能不使用动态分配,索引不能超过最大索引。
 */
int UI_Menu_Link(ui_menu_t* parent,ui_menu_t* item,uint8_t itemIndex)
{
    if(item == NULL)
    {
        return -1;
    }
    if(itemIndex >= UI_MENU_ITEM_MAX)
    {
        return -1;
    }
    if(parent == NULL)
    {
        return -1;
    }
    item->level = parent->level + 1;        // 将当前项设置为父菜单的下一级
    item->parent = parent;
    parent->items[itemIndex] = item;
    return 0;
}

ui_menu_t* UI_Menu_Top_Get(ui_menu_t* item)
{
    ui_menu_t* top = item;
    if(top != NULL)
    {
        while(top->parent != NULL){
            top = top->parent;
        }
    }
    return top;

    
}

菜单的调用方式,根据不同的按键执行对应的功能。

cpp 复制代码
void UI_Page_Menu_Handler(uint16_t key)
{
    uint16_t keyEvent = key;
    uint8_t isSave = 0;     

    if(keyEvent == KEY_OK)      // 保存参数,进入下一步
    {
        if(curMenu->on_Key_OK)
        {
            curMenu = curMenu->on_Key_OK(&isSave);      // 调用当前菜单的OK
            if(curMenu->menu_Enter)
            {
                if(curMenu->level > lastMenu->level)
                {
                    curMenu->menu_Enter(lastMenu->itemID);
                }
            }
            lastMenu = curMenu;
        }
        else
        {
            isSave = 0xFF;
        }
        
        if(isSave == 1)      // 保存数据
        {

        }
        else if(isSave == 0)
        {

        }        
    }
    else if(keyEvent == KEY_BACK)
    {
        if(curMenu->menu_Exit)
        {
            curMenu->menu_Exit();
        }
        if(curMenu->on_Key_Back)
        {
            curMenu = curMenu->on_Key_Back();
            lastMenu = curMenu;
        }

    }
    else if(keyEvent == KEY_UP)
    {
        if(curMenu->on_Key_Up)
        {
            if(curMenu->on_Key_Up())
            {

            }
            else
            {

            }
        }        
    }
    else if(keyEvent == KEY_DOWN)
    {
        if(curMenu->on_Key_Down)
        {
            if(curMenu->on_Key_Down())
            {

            }
            else
            {

            }
        }
        
    }  
    curMenu->menu_Show();
}

本框架没有使用动态内存分配。在菜单分级较多的情况下,没有框架的支持,写起来会显得非常混乱。在框架的支持下,可以将各个菜单功能解耦合,利于后期的维护及扩展。

相关推荐
LCG米15 小时前
STM32硬件CRC外设实测:多项式固定陷阱、CRC-32校验不匹配根因与软件查表法耗时对比落地
stm32·单片机·嵌入式硬件
La Pulga19 小时前
【FreeRTOS源码学习笔记】任务切换
单片机·mcu·学习·嵌入式·freertos·实时操作系统
女神下凡1 天前
芯参谋(85):Linux_PPI_NAND_驱动开发指南
linux·运维·arm开发·驱动开发·单片机·嵌入式硬件·设计规范
Autumn_ing1 天前
Pixso AI 如何按团队设计规范生成 UI?以消息设置页说明选库与验收
人工智能·ui·设计规范·pixso
硅基手札1 天前
【Linux 内核专栏 19】20 · 嵌入式子系统 — GPIO·pinctrl·clock·regulator
linux·运维·单片机·linux内核·嵌入式开发·调试定位
何粥学1 天前
Vivado 2024.2 开发记录(AC820 Zynq-7020)——软件使用,点亮led灯
单片机·嵌入式硬件·zynq
Sakura_j_h_1 天前
51 单片机驱动四位数码管:动态扫描、限流电阻与消影的取舍
单片机·嵌入式硬件·51单片机·嵌入式·数码管·动态扫描·限流电阻
不磕了还不行1 天前
用 Vue + Element UI 把元宝搜索的返回值做成“能点开检查的证据卡片”
前端·vue.js·ui
蹊黎2 天前
Linux 下用 C 语言实现进度条
linux·c语言·单片机
用户8351414049492 天前
const的四种位置,含义完全不同
嵌入式·源码