多級菜單編程實現
1)菜單結構
菜單結構採用樹狀結構,由若干個節點組成多級菜單。每個節點由當前層級節點數、標題,操作函數、父節點和子節點構成,如下代碼所示。
typedef struct Menu{
uint8_t MenuNodes; //當前層節點數目
char *MenuName; //菜單標題
void (*func)(uint16_t key); //節點函數
const struct Menu *Parent; //父節點
const struct Menu *Child; //子節點
}Menu_typedef;
2)菜單定義
這裏我們實現一個多媒體管理菜單
【我的音樂】
----【經典音樂】
--------【曲目1】
--------【曲目2】
----【流行音樂】
【我的文檔】
----【電子書】
----【說明書】
代碼實現如下:
const Menu_typedef MainMenu[2] = { //一級菜單
{2, "我的音樂", NullSubs, NULL, MusicMenu},
{2, "我的文檔", NullSubs, NULL, DocMenu}
};
const Menu_typedef MusicMenu[2] = { //二級菜單
{2, "經典音樂", NullSubs, MainMenu, Music_1_Menu},
{2, "流行音樂", NullSubs, MainMenu, NULL}
};
const Menu_typedef DocMenu[2] = { //二級菜單
{2, "電子書", NullSubs, MainMenu, Doc_1_Menu},
{2, "說明書", NullSubs, MainMenu, NULL}
};
const Menu_typedef Music_1_Menu[2] = { //三級菜單
{2, "曲目1", MusicPlayer, MusicMenu, NULL},
{2, "曲目2", MusicPlayer, MusicMenu, NULL},
};
const Menu_typedef Doc_1_Menu[1] = { //三級菜單
{2, "語文", Reader, DocMenu, NULL}
};
定義一個節點,用來保存當前節點信息,初始化指向主菜單
Menu_typedef *MenuPoint = (Menu_typedef*)MainMenu;
char UserChoose = 0; //當前層級節點序號
定義一個空函數,補充沒有操作的節點。
void NullSubs(uint16_t key)
{
}
實現音樂播放函數(省略)
void MusicPlayer(uint16_t key)
{
switch(UserChoose){
case 0:
//play music 1
break;
case 1:
//play music 2
break;
}
}
實現文檔閱讀器(省略)
void MusicPlayer(uint16_t key)
{
if(key == )
switch(UserChoose){
case 0:
//語文
break;
}
}
3)菜單操作
菜單操作由以下功能組成:上、下、返回、確定。
菜單任務的入口函數爲按鍵操作值,根據用戶的輸入設備傳入
/**
* @brief 菜單選擇.
* @Note
* @param keyvalue 輸入按鍵
* @retval None
*/
void MenuTask(uint16_t Keyvalue)
{
if(OperationFunc == 0)
{
if(Keyvalue)
{
switch(Keyvalue)
{
case UP: //向上
UserChoose--;
if (UserChoose < 0)
{
UserChoose = MenuPoint->MenuNodes - 1; //跳轉到最後一項
}
break;
case ESC: // 返回
OperationFunc = 0;
if (MenuPoint[UserChoose].Parent != NULL) //父級是否存??
{
MenuPoint = (Menu_typedef*)MenuPoint[UserChoose].Parent;
UserChoose = 0;
}
break;
case DOWN: //向下
UserChoose ++;
if (UserChoose > MenuPoint->MenuNodes - 1)
{
UserChoose = 0; //跳轉到子級菜單的第一項
}
break;
case ENTER: // ENTER
if (MenuPoint[UserChoose].func != NullSubs) //判斷是否有行爲函數
{
Flag.OperationFunc = 1; //啓動函數操作標誌
layernumber++;
}
else if (MenuPoint[UserChoose].Child != NULL) //判斷子級是否爲空
{
MenuPoint = (Menu_typedef*)MenuPoint[UserChoose].Child; //進入子級
UserChoose = 0; //跳轉到子級菜單的第一
}
break;
}
}
Keyvalue = 0; //清零,防止直接ENTER
Dipstr = MenuPoint[UserChoose].MenuName; //保存當前菜單標題,輸出到顯示設備
}
if(OperationFunc == 1)
{
(*MenuPoint[UserChoose].func)(Keyvalue); //執行函數操作
}
}
4)結語
這個樹狀菜單結構具備較好的擴展性和移植性,可以很方便的移植到其他平臺,而且結構使用穩定,有問題請留言。