­

輕量級多級菜單控制框架程式(C語言)

1、前言

        作為嵌入式軟體開發,可能經常會使用命令行或者顯示器等設備實現人機交互的功能,功能中通常情況都包含 UI 菜單設計;很多開發人員都會有自己的菜單框架模組,防止重複造輪子,網上有很多這種菜單框架的程式碼,但是大多耦合性太強,無法獨立出來適配不同的菜單設計。

        本文介紹一個降低了耦合性,完全獨立的菜單框架,菜單顯示風格和顯示平台完全由自己根據需求設計,而菜單操作統一由菜單模組處理即可,提高程式的移植性。


2、介紹

菜單框架程式碼主要特點有:

  • 採用鏈表方式實現多級菜單(通過配置選擇採用動態分配或者數組實現)
  • 菜單框架作為獨立模組,拒絕和按鍵模組、顯示模組進行耦合
  • 在十分獨立的情況下,也保證不受菜單的顯示風格和顯示平台影響,可自由選擇設計顯示風格和顯示平台
  • 快捷菜單操作等
  • 可以採用表驅動的方式初始化菜單,提高程式碼的可讀性

3、程式碼功能

源文件部分程式碼如下:

/**
  * @brief      菜單初始化
  * 
  * @param[in]  pMainMenu    主菜單註冊資訊
  * @param[in]  num          主菜單數目
  * @param[in]  fpnShowMenu  主菜單顯示效果函數
  * @return     0,成功; -1,失敗 
  */
int Menu_Init(MenuRegister_t *pMainMenu, uint8_t num, ShowMenuCallFun_f fpnShowMenu)
{
    MenuCtrl_t *pMenuCtrl = NULL;

#if MENU_MAX_DEPTH != 0
    sg_currMenuDepth = 0;
#endif

    if ((pMenuCtrl = NewMenu()) != NULL)
    {
        pMenuCtrl->pLastMenuCtrl = NULL;
        pMenuCtrl->pfnShowMenuFun = fpnShowMenu;
        pMenuCtrl->pMenuInfo = pMainMenu;
        pMenuCtrl->menuNum = num;
        pMenuCtrl->currPos = 0;
        pMenuCtrl->isRunCallback = 0;

        sg_tMenuManage.pCurrMenuCtrl = pMenuCtrl;

        return 0;
    }

    return -1;
}

頭文件部分程式碼如下:

/**
  * @brief 菜單資訊註冊結構體
  * 
  */
typedef struct MenuRegister
{
    const char     *pszDesc;            /*!< 當前選項的中文字元串描述 */

    const char     *pszEnDesc;          /*!< 當前選項的英文字元串描述 */

    menusize_t      subMenuNum;         /*!< 當前選項的子菜單數目, 子菜單數目為0則表示下一級非菜單介面, 會執行非菜單功能函數 */

    struct MenuRegister *pSubMenu;      /*!< 當前選項的子菜單內容 */

    ShowMenuCallFun_f pfnShowMenuFun;   /*!< 當前選項的子菜單顯示效果函數, 為NULL則延續上級菜單顯示效果 */

    MenuCallFun_f     pfnEnterCallFun;  /*!< 當前選項確定進入時需要執行的函數, 為NULL不執行 */

    MenuCallFun_f     pfnExitCallFun;   /*!< 當前選項進入後在退出時需要執行的函數, 為NULL不執行 */

    MenuCallFun_f     pfnRunCallFun;    /*!< 當前選項的非菜單功能函數, 只有當菜單數目為0有效, 為NULL不執行 */

    void             *pExtendData;      /*!< 當前選項的菜單顯示效果函數擴展數據入參, 可自行設置該內容 */
}MenuRegister_t;

/* Exported constants ------------------------------------------------------------------------------------------------*/
/* Exported macro ----------------------------------------------------------------------------------------------------*/

#define GET_MENU_NUM(X)    (sizeof(X) / sizeof(MenuRegister_t))

/* Exported functions ------------------------------------------------------------------------------------------------*/

/* 菜單初始化和反初始化 */
extern int Menu_Init(MenuRegister_t *pMainMenu, uint8_t num, ShowMenuCallFun_f fpnShowMenu);
extern int Menu_DeInit(void);

/* 菜單功能設置 */
extern menubool Menu_IsEnglish(void);
extern int Menu_SetEnglish(menubool isEnable);

/* 菜單選項顯示時需要使用的功能擴展函數 */
extern int Menu_UpdateShowBase(MenuShow_t *ptMenuShow, menusize_t showNum);

/* 菜單狀態獲取函數 */
extern menubool Menu_IsRun(void);
extern menubool Menu_IsMainMenu(void);
extern menubool Menu_IsAtMenu(void);

/* 菜單操作 */
extern int Menu_Reset(void);
extern int Menu_Enter(void);
extern int Menu_Exit(uint8_t isReset);
extern int Menu_SelectPrevious(uint8_t isAllowRoll);
extern int Menu_SelectNext(uint8_t isAllowRoll);

/* 菜單輪詢處理任務 */
extern int Menu_Task(void);

4、示例程式碼顯示效果

示例程式碼採用的平台是命令行輸出輸入顯示效果

demo中提供了如何實現圖形菜單(主菜單有點粗糙)、普通列表菜單、右側彈窗菜單(更多設置)等效果演示,菜單樣式可自由擴展,足夠自由;快捷菜單操作、中英文切換演示。(windows中編譯需要將 demo.c轉 GBK 編碼,Linux 轉 utf8 編碼,不然可能出現漢字亂碼的問題)

以下是通過單片機驅動 OLED 顯示的菜單介面顯示效果


5、示例程式碼獲取鏈接

下載鏈接點擊:輕量級菜單框架(最新的功能可切換 develop 分支)