📄
字号:
/*[原创]一个树形多级菜单参考程序
这是一个用于车载电话的菜单程序,可以看成是手机功能菜单的简化板.
我所认为的树形多级菜单是指:在一个父菜单项目下面有多个子菜单,
子菜单下面又有多个孙菜单...,进入下层菜单主要依*当前选中的索引.有点象文件的目录结构.
本木从前实现这类的菜单主要*分层的switch语句,每层都是一个switch.但当我看到晓奇大侠的
程序和耳朵灌满lq等人的争论后,那时那地,我的心境变化了,我意识到指针代表了先进的生产力,
代表了社会的发展方向,是建设和谐社会的必要条件.不管你用了多长时间C语言,只要你不善于用
一个小针指来指去,你就是那种"用嘴吃饭的高贵骑士,决不用屁股装弹步枪"的守旧分子和社会发
展的绊脚石.(跑题太远,删去1万字...打住)
.言归正传,下面的程序适用CPU为Mega16,编译器为CVAVR 1.24.4a;由于按键数目较多,所以按键程
序把按键事件分为数字键,快捷键,确认键,取消键,上下翻键几类,以减小菜单结构的容量.一下菜单
数据在菜单结构数组中的偏移量,有多少个菜单象就有多少个宏定义*/
#define DIAL00_MENU 1
#define SET00_MENU 2
#define DIAL01_MENU 3
#define SET01_MENU 4
#define SET02_MENU 5
#define SET03_MENU 6
#define SET04_MENU 7
#define SET05_MENU 8
//功能函数说明
void MainFace(void);
void EditCodeFace(void);
void MFunListFace(void);
void TranTelCodeFace(void);
void FCodeListFace(void);
void CallRecListFace(void );
void GroupFunListFace(void );
void SysFunListFace(void );
void TelNoteListFace(void );
//重头戏:
//定义用于菜单操作得结构
typedef flash struct {
unsigned int fatherMenu; //父菜单偏移地址
unsigned int ownIndex; //本身地偏移地址
unsigned int mNumKeyFunc; // 数字按键时指向的菜单结构
unsigned int mFastKeyFunc; // 数字按键时指向的菜单结构
unsigned int mYesKeyFunc; // YES键时指向的菜单结构
unsigned int mNoKeyFunc; // NO键时指向的菜单结构
unsigned int mUpKeyFunc; // UP键时指向的菜单结构
unsigned int mDownKeyFunc; //DOWN键时指向的菜单结构
void(*menuFunc)(void);
}_menu;
flash _menu menuList[] ={
//主菜单 偏移 0
{ MAIN_MENU,MAIN_MENU,
DIAL00_MENU, DIAL00_MENU, DIAL00_MENU, IN_MENU, SET00_MENU, SET00_MENU, MainFace},
//拨号第一屏---号码编辑 偏移 1
{ MAIN_MENU,DIAL00_MENU,
DIAL00_MENU, DIAL00_MENU, DIAL01_MENU, DIAL00_MENU, USELESS, USELESS, EditCodeFace},
//设定第一屏---功能列表 偏移 2
{ MAIN_MENU,DIAL00_MENU,
USELESS, USELESS, SET00_MENU, MAIN_MENU, SET00_MENU, SET00_MENU, MFunListFace},
//拨号第二屏---拨号通话 偏移 3
{ MAIN_MENU,DIAL01_MENU,
USELESS, USELESS, USELESS, MAIN_MENU, USELESS, USELESS, TranTelCodeFace},
//速拨第一屏---号码列表 偏移 4
{ SET00_MENU,SET01_MENU,
USELESS, USELESS, SET11_MENU, SET00_MENU, SET01_MENU, SET01_MENU, FCodeListFace},
//通话记录第一屏---号码列表 偏移 5
{ MAIN_MENU,DIAL00_MENU,
USELESS, USELESS, SET00_MENU, SET00_MENU, SET02_MENU, SET02_MENU, CallRecListFace},
//集群设定第一屏---功能列表 偏移 6
{ MAIN_MENU,DIAL00_MENU,
USELESS, USELESS, SET00_MENU, SET00_MENU, SET03_MENU, SET03_MENU, GroupFunListFace},
//系统设定第一屏---功能列表 偏移 7
{ MAIN_MENU,DIAL00_MENU,
USELESS, USELESS, SET00_MENU, SET00_MENU, SET04_MENU, SET04_MENU, SysFunListFace},
//电话本第一屏--- 记录列表 偏移 8
{ MAIN_MENU,DIAL00_MENU,
USELESS, USELESS, SET00_MENU, SET00_MENU, SET05_MENU, SET05_MENU, TelNoteListFace}
};
//定义每个菜单项下面的子菜单相对父菜单的偏移,如果不用全局索引,此项为零
.flash unsigned char gMain_SubLoc[] ={0,0};
flash unsigned char gDial00_SubLoc[] ={0};
flash unsigned char gDial01_SubLoc[] ={0};
flash unsigned char gSet00_SubLoc[] ={
SET01_MENU-SET00_MENU,
SET02_MENU-SET00_MENU,
SET03_MENU-SET00_MENU,
SET04_MENU-SET00_MENU,
SET05_MENU-SET00_MENU
};
flash unsigned char *pSubMenu
;//同上面的数组配合确定按YES键时转向的子菜单
flash _menu *pCurrMenu;调用程序:
void KeyMenu(){
//旧情难舍还是用了一个switch
if (gKeyValue != NULL){
switch (gKeyAttr){
case NUM_KEY:
SwitchMenu(pCurrMenu->mNumKeyFunc);
break;
case FAST_KEY:
SwitchMenu(pCurrMenu->mFastKeyFunc);
break;
case YES_KEY:
SwitchMenu((*(pSubMenu+gMenuLocIndex))+pCurrMenu-
>mYesKeyFunc);
gMenuLocIndex=0;
break;
case NO_KEY:
SwitchMenu(pCurrMenu->mNoKeyFunc);
break;
case UP_KEY:
SwitchMenu(pCurrMenu->mUpKeyFunc);
break;
case DOWN_KEY:
SwitchMenu(pCurrMenu->mDownKeyFunc);
break;
default:break;
}
gKeyValue = NULL;
}
if (pCurrMenu->ownIndex == MAIN_MENU) pCurrMenu->menuFunc();
}
/********************************************
菜单功能函数功能:
根据输入参数确定菜单指针转向,并执行转向后的菜单功能参数:
菜单指针相对偏移返回:
无执行返回:FALSE,
有执行返回:TRUE
影响:pCurrMenu
*********************************************/
BOOL SwitchMenu(unsigned int menuIndex){
if (menuIndex == USELESS) return FALSE;
pCurrMenu = &menuList[menuIndex];
pCurrMenu->menuFunc();
return TRUE;
}
/*如果要添加菜单,
步骤是:
1.在菜单数据结构中增加记录项,
2.添加记录项所在位置的宏定义
3.定义使用全局索引的子目录相对偏移
总结:这个程序结构最大功绩在于简化了KeyMenu()的结构.
用的FLASH好像小了点,菜单复杂时的可读性太差.*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -