树立一个树状的菜单结构,用链表完成
链表中包括:
1、指向同级左右菜单和指向父菜单、子菜单的四个菜单结构体指针;
2、进入该菜单时需求履行的初始化函数指针
3、退出该菜单时需求履行的完毕函数指针
4、该菜单内的按键处理函数指针数组的指针操作菜单模块需求的按键操作有:左、右、确
认、退出。
选用这种方法,能够便利的添加或删减菜单。而且只需求在其头文件中修正初始变量就可
以完成,彻底无须修正C文件中的任何函数。
详细结构界说
我的界说,做个参阅:
#defineMENU_HLP_EN//菜单协助信息使能
typedef struct
{
void (*pMenuTaskInit)(void);//指向菜单使命初始化函数的指针
void (*pMenuTaskEnd)(void);//指向菜单使命完毕函数的指针
}MENU_TASK_TYP;
typedef struct MenuTyp
{
INT8U*MenuName;//菜单称号字符串
WORK_MODWorkMod;//作业状况编号
MENU_TASK_TYP*pMenuTask;//指向菜单使命的指针
void (**pTaskKeyDeal)(void);//指向菜单使命按键处理函数数组的指针
#ifdef MENU_HLP_EN
INT8U*MenuHlp;//菜单协助字符串
#endif
struct MenuTyp*pParent;//指向上层菜单的指针
struct MenuTyp*pChild;//指向子菜单的指针
struct MenuTyp*pRight;//指向右菜单的指针
struct MenuTyp*pLeft;//指向左菜单的指针
}MENU_TYP;
我依据网上的材料做的一个菜单:
struct KeyTabStruct{
uint8MenuIndex;//当时状况索引号
uint8MaxItems;//本级菜单最大条目数
uint8ShowLevel;//菜单显现内容
uint8PressOk;//按下”回车”键时转向的状况索引号
uint8PressEsc;//按下”回来”键时转向的状况索引号
uint8PressDown;//按下”向下”键时转向的状况索引号
uint8PressUp;//按下”向上”键时转向的状况索引号
void(*CurrentOperate)();//当时状况应该履行的功用操作
};
uint8MenuID;//菜单ID号
uint8MenuNextID;//下级菜单ID号
//CurMenuID=本菜单ID
//MaxMenuItem=同级菜单最大项数
//OkMenuID=子菜单层所对应的菜单ID,ID=999为菜单现已究竟了
//EscMenuID=父菜单层所对应的菜单ID,ID=999为菜单现已到顶了
//DownMenuID=弟菜单层所对应的菜单ID,ID=999为菜单是独生子
//UpMenuID=兄菜单层所对应的菜单ID,ID=999为菜单是独生子
//CurFunction=本菜单所对应的菜单函数指针
const struct KeyTabStruct KeyTab[MAX_KEYTABSTRUCT_NUM]={
//CurMenuID,axMenuItem,MenuShowLevel,OkMenuID,EscMenuID,DownMenuID,UpMenuID,CurFunction
{MENU_EDIT,0,0,MENU_DATA_VIEW,MENU_NO,MENU_NO,MENU_NO,*MenuEdit},
{MENU_DATA_VIEW,3,1,MENU_DATA_VIEW_FIRE,MENU_EDIT,MENU_SYS_EDIT,MENU_PRINT_DATA,*MenuEdit},
{MENU_DATA_VIEW_FIRE,5,MENU_NO,MENU_NO,MENU_DATA_VIEW,MENU_DATA_VIEW_TROUBLE, MENU_STEP_FOLLOW, *MenuDataViewIn},
{MENU_DATA_VIEW_TROUBLE, 5,MENU_NO,MENU_NO,MENU_DATA_VIEW,MENU_DATA_VIEW_REPEAT,MENU_DATA_VIEW_FIRE,*MenuDataViewIn},
{MENU_DATA_VIEW_REPEAT,5,MENU_NO,
MENU_NO,MENU_DATA_VIEW,MENU_FACE_CHECK,
MENU_DATA_VIEW_TROUBLE,*MenuDataViewIn},
{MENU_FACE_CHECK,5,MENU_NO,
MENU_NO,MENU_DATA_VIEW,MENU_STEP_FOLLOW,
MENU_DATA_VIEW_REPEAT,*MenuFaceCheck},
{MENU_STEP_FOLLOW,5,MENU_NO,
MENU_NO,MENU_DATA_VIEW,MENU_DATA_VIEW_FIRE,MENU_FACE_CHECK,
*MenuStepFollow},
{MENU_SYS_EDIT,3,
2,MENU_SUM_SET,MENU_EDIT,
MENU_PRINT_DATA,MENU_DATA_VIEW,*MenuEdit},
{MENU_SUM_SET,6,MENU_NO,
MENU_NO,MENU_SYS_EDIT,MENU_EDIT_INSULATE,
MENU_TIME_SET,*MenuSumSet},
{MENU_EDIT_INSULATE,6,MENU_NO,
MENU_NO,MENU_SYS_EDIT,MENU_EDIT_HZ,MENU_SUM_SET,
*MenuEditInsulate},
{MENU_EDIT_HZ,6,MENU_NO,
MENU_NO,MENU_SYS_EDIT,MENU_LD_CONTROL,
MENU_EDIT_INSULATE,*MenuEditHZ},
{MENU_LD_CONTROL,6,
MENU_NO,MENU_NO,MENU_SYS_EDIT,MENU_LD_DELAY,
MENU_EDIT_HZ,*MenuLDControl},
{MENU_LD_DELAY,6,
MENU_NO,MENU_NO,MENU_SYS_EDIT,MENU_TIME_SET,
MENU_LD_CONTROL,*MenuLDDelay},
{MENU_TIME_SET,6,MENU_NO,
MENU_NO,MENU_SYS_EDIT,MENU_SUM_SET,MENU_LD_DELAY,
*MenuTimeSet},
{MENU_PRINT_DATA,3,3,
MENU_PRINT_DATA_FIRE,MENU_EDIT,MENU_DATA_VIEW,
MENU_SYS_EDIT,*MenuEdit},
{MENU_PRINT_DATA_FIRE,4,
MENU_NO,MENU_NO,MENU_PRINT_DATA,
MENU_PRINT_DATA_TROUBLE,MENU_PRINT_SET,*MenuPrintDataIn},
{MENU_PRINT_DATA_TROUBLE,4,MENU_NO,
MENU_NO,MENU_PRINT_DATA,MENU_PRINTER_CHECK,
MENU_PRINT_DATA_FIRE,*MenuPrintDataIn},
{MENU_PRINTER_CHECK,4,MENU_NO,
MENU_NO,MENU_PRINT_DATA,MENU_PRINT_SET,
MENU_PRINT_DATA_TROUBLE,*MenuPrintDataIn},
{MENU_PRINT_SET,4,MENU_NO,
MENU_NO,MENU_PRINT_DATA,MENU_PRINT_DATA_FIRE,
MENU_PRINTER_CHECK,*MenuPrintSet},
};
const struct MenuDispDataMenuEditShow[][MENU_MAX] = {
{{MENU_NO, 0, 0, “挑选:消音→退出”},//主菜单
{MENU_DATA_VIEW, 1, 6, “⒈数据检查”},
{MENU_SYS_EDIT, 2, 6, “⒉体系编程”},
{MENU_PRINT_DATA, 3, 6, “⒊数据打印”}},
{{MENU_NO, 0, 0, “数据检查:消音→退出”},//数据查
看
{MENU_DATA_VIEW_FIRE, 1, 4, “⒈火灾”},
{MENU_DATA_VIEW_TROUBLE, 2, 4, “⒉毛病”},
{MENU_DATA_VIEW_REPEAT , 3, 4, “⒊重码”},
{MENU_FACE_CHECK, 1,12, “⒋面板检测”},
{MENU_STEP_FOLLOW, 2,12, “⒌单步盯梢”}},
{{MENU_NO, 0, 0, “体系编程:消音→退出”},//体系编程
{MENU_SUM_SET, 1, 0, “⒈容量设置”},
{MENU_EDIT_INSULATE, 2, 0, “⒉阻隔点”},
{MENU_EDIT_HZ, 3, 0, “⒊汉字描绘”},
{MENU_LD_CONTROL, 1,12, “⒋联动操控”},
{MENU_LD_DELAY, 2,12, “⒌模块延时”},
{MENU_TIME_SET, 3,12, “⒍时钟调整”}},
{{MENU_NO, 0, 0, “数据打印:消音→退出”},//数据打印
{MENU_PRINT_DATA_FIRE, 1, 0, “⒈火灾数据”},
{MENU_PRINT_DATA_TROUBLE,2, 0, “⒉毛病数据”},
{MENU_PRINTER_CHECK, 3, 0, “⒊打印机自检”},
{MENU_PRINT_SET, 1,12, “⒋打印设置”}},
};
void WaitKey(void)
{
uint32 time;
time = RTCFlag;
WhichKey = KEY_NONE;
while(!EscFlag){
if(RTCFlag – time >= EDIT_TIME)
EscFlag = TRUE;
if(WhichKey != KEY_NONE){
KeySound(300);//按键音
return;
}
}
}
void MenuEdit()
{
uint32 i,j=0;
uint32 oldid;
j = KeyTab[MenuID].ShowLevel;
if(WhichKey == KEY_ESC || WhichKey == KEY_OK){
ClearScreen();
for(i=0;i
ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j]
[i].Column,MenuEditShow[j][i].Pdata,0);//初始化显现
oldid =
0;
//没有原先挑选的项
}else{
if(WhichKey == KEY_UP)
oldid = KeyTab[MenuNextID].PressDown;
else
oldid = KeyTab
[MenuNextID].PressUp;
//指示原先的项
}
for(i=1;i
if(MenuEditShow[j][i].Id == oldid)
ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j]
[i].Column,MenuEditShow[j][i].Pdata,0);//正常显现原先的项
else{
if(MenuEditShow[j][i].Id == MenuNextID)
ShowString(MenuEditShow[j][i].Lin,MenuEditShow
[j][i].Column,MenuEditShow[j][i].Pdata,1);//反显当时挑选的项
}
}
WhichKey = KEY_NONE;
}
uint32 Edit(void)
{
struct KeyTabStruct NowKeyTab;//指示当时的菜单值
uint32 escflag = FALSE;
ResetFlag = FALSE;
ChangeFlag = FALSE;
EscFlag = FALSE;
MenuID = MENU_EDIT;
NowKeyTab = KeyTab[MenuID];
MenuNextID = NowKeyTab.PressOk;
(*NowKeyTab.CurrentOperate)();//显现主菜单
do{
if(WhichKey == KEY_NONE)
WaitKey();//等候按键
switch(WhichKey){
case KEY_ESC : if(NowKeyTab.PressEsc != MENU_NO)
{
MenuID =
NowKeyTab.PressEsc;
MenuNextID =
NowKeyTab.MenuIndex;
NowKeyTab = KeyTab
[MenuID];
NowKeyTab.PressOk =
MenuNextID;
(*NowKeyTab.CurrentOperate)
();//显现当时菜单
}else
escflag =
TRUE;//退出编程状况
break;
case KEY_OK:if(NowKeyTab.PressOk != MENU_NO)
{
MenuID =
NowKeyTab.PressOk;
NowKeyTab = KeyTab
[MenuID];
MenuNextID =
NowKeyTab.PressOk;
}
(*NowKeyTab.CurrentOperate)
();//履行当时按键的操作
break;
case KEY_UP:if((MenuNextID != MENU_NO) &&
(KeyTab[MenuNextID].PressUp != MENU_NO)){
NowKeyTab.PressOk =
KeyTab[MenuNextID].PressUp;
MenuNextID = KeyTab
[MenuNextID].PressUp;
(*NowKeyTab.CurrentOperate)();//履行当时按键的操作
}
break;
case KEY_DOWN:if((MenuNextID != MENU_NO) &&
(KeyTab[MenuNextID].PressDown != MENU_NO)){
NowKeyTab.PressOk =
KeyTab[MenuNextID].PressDown;
MenuNextID = KeyTab
[MenuNextID].PressDown;
(*NowKeyTab.CurrentOperate)();//履行当时按键的操作
}
break;
case KEY_RESET: ResetFlag = TRUE;
break;
default: break;
}
}while(!ResetFlag && !EscFlag && !escflag);
if(ChangeFlag && !EscFlag && !ResetFlag)
EditDataChange();
if(ResetFlag)
returnSYS_RESET;
else{
return0;
}
}
关于这个菜单的阐明:
1.我用的是ARM处理器,所以51的时分把const改成code,uint32改成unsigned char。
2.在网上的材猜中,结构体数组是存在RAM中的,我把它放在也flash中了,然后再界说一个
结构体变量,就样就能够省许多RAM,比较合适51.
3.在网上材猜中,由于保存了本来的挑选,当你脱离编程状况从头进行后,会发现挑选上会
是本来进行的次序,我改动之后,退出上一级菜单仍是你选的那一项,但从头进入后便是第
一个指定项。
4.添加UP和DOWN显现,能够反显最新选定的选项,正常显现本来的选项。
声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/chuanganqi/257438.html