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 分支)