在很多项目中我们都需要菜单,特别是多层菜单应用比较广泛,但是写一个能够很方便移植的多层菜单非常麻烦,我们这里就先研究一下单层菜单的翻滚的实现方式。
下面就以一个例子来说明此菜单的具体实现方法:
1. 假设本菜单使用在128*64的点阵LCM上。
2. 菜单显示为3行,一行为菜单项目名称。
3. 菜单选择项反白显示。
4. 一个采用5个按键:UP,DOWN,OK,LEFT,RIGHT。及上、下、左、右和确定键。
那么菜单可能产生的效果应该有以下18种情况:
从上面的图不难看出,8个菜单项,每次显示3项,最多有6种可能,而每一只种又有3种光标显示,所以一共就有18中显示状态。那么如果我们要通过上下按键来实现这几
种菜单的显示,我们就必须找到它们之间的规律。认真看看图,看它们究竟有什么样的规律,开动你的大脑吧!!!!!!!!
下面把它们的规律找出来:
1.横着3项菜单内容相同,只是光标位置不同,所以我们把横着相同的用页表示,一共分为6也Page = 0~5。
2.竖着6项光标相同,一共有3种可能,用Cursor = 0~2表示。
我们把每个菜单Page和Cursor已经这两个参数的和Sum表示出来,那么我们就能完全掌握它们的所有规律的了。。。。。。。。。
我们可以看出Sum相同的菜单,其光标位置是相同的,所以,我们只有控制好Cursor和Page两个变量就可以实现菜单的翻滚了。。。。。。
很多网友不太理解菜单的翻滚方式,这里
特做了两个简单的动画,一个上一直按上键,一个是一直按下键的动画,其他按键方式内同。。。。。。。。。。
上键
下键
有了上面的理论基础,下面的代码实现并不难:
1.定义菜单结构体:
// 菜单参数
typedef struct _MENU_PRMT { uint8 Cursor; // 光标值(当前光标位置) uint8 PageNo; // 菜单页(显示开始项) uint8 Index; // 菜单索引(当前选择的菜单项) uint8 DispNum; // 显示项数(每页可以现在菜单项) uint8 MaxPage; // 最大页数(最大有多少种显示页) } MENU_PRMT; extern MENU_PRMT MenuPrmt;
// 菜单执行 typedef struct _MENU_TABLE { uint8 *MenuItem; // 菜单项目名称 void (*ItemHook)(void); // 要运行的菜单函数 } MENU_TABLE;
2.菜单项定义
MENU_TABLE MMenu[M_MENU_NUM] = // 管理菜单 { {"1.时间设定 ", App_SetClock}, // 时钟设置 {"2.系统参数 ", App_SetSysPrmt}, // 参数设置 {"3.教学参数 ", App_SetTeachPrmt}, // 教学参数 {"4.下载参数 ", App_DownloadPrmt}, // 下载参数 {"5.清除存储 ", App_ClearStorage}, // 清除存储 {"6.校对速度 ", App_ProofSpeed}, // 速度校对 {"7.退出管理 ", App_ExitMenu}, // 退出管理 {"8.其他设置 ", App_Other}, // 其他设置 };
//3.初始化菜单参数 /************************************************************************************** * FunctionName : AppMenuPrmtInit() * Description : 初始化菜单参数 * EntryParameter : None * ReturnValue : None **************************************************************************************/ void AppMenuPrmtInit(void) { MenuPrmt.Cursor = 0; // 光标清零 MenuPrmt.PageNo = 0; // 页清零 MenuPrmt.Index = 0; // 索引清零 } //4.菜单显示设置 /************************************************************************************** * FunctionName : App_MenuSet() * Description : 设置菜单显示 * EntryParameter : num - 页菜单显示项,page - 最多页数 * ReturnValue : None **************************************************************************************/ void App_MenuSet(uint8 num, uint8 page) { MenuPrmt.DispNum = num; // 页最多显示项目数 MenuPrmt.MaxPage = page; // 最多页数 } //5.菜单显示 /************************************************************************************** * FunctionName : App_MenuDisplay() * Description : 显示菜单 * EntryParameter : page - 显示页,dispNum - 每一页的显示项,cursor - 光标位置 * ReturnValue : None **************************************************************************************/ void App_MenuDisplay(MENU_TABLE *menu, uint8 page, uint8 dispNum, uint8 cursor) { uint8 i; for (i=0; i { if (cursor == i) { LCMDisplayStrRvs(0, (i+1)*2, menu[page+i].MenuItem); // 反白显示菜单项 } else { LCMDisplayStr(0, (i+1)*2, menu[page+i].MenuItem); // 显示菜单项 } } } //6.菜单翻滚 /************************************************************************************** * FunctionName : App_MenuMove() * Description : 菜单移动 * EntryParameter : None * ReturnValue : 有确认返回0,否则返回1 **************************************************************************************/ uint8 App_MenuMove(uint8 key) { uint8 rValue = 1; switch (key) { case KV_UP: // 向上 if (MenuPrmt.Cursor != 0) // 光标不在顶端 { MenuPrmt.Cursor--; // 光标上移 } else // 光标在顶端 { if (MenuPrmt.PageNo != 0) // 页面没有到最小 { MenuPrmt.PageNo--; // 向上翻 } else { MenuPrmt.Cursor = MenuPrmt.DispNum-1; // 光标到底 MenuPrmt.PageNo = MenuPrmt.MaxPage-1; // 最后页 } } break; case KV_DN: // 向下 if (MenuPrmt.Cursor < MenuPrmt.DispNum-1) // 光标没有到底,移动光标 { MenuPrmt.Cursor++; // 光标向下移动 } else // 光标到底 { if (MenuPrmt.PageNo < MenuPrmt.MaxPage-1) // 页面没有到底,页面移动 { MenuPrmt.PageNo++; // 下翻一页 } else // 页面和光标都到底,返回开始页 { MenuPrmt.Cursor = 0; MenuPrmt.PageNo = 0; } } break; case KV_MD: // 确认 MenuPrmt.Index = MenuPrmt.Cursor + MenuPrmt.PageNo; // 计算执行项的索引 rValue = 0; break; default:break; } return rValue; // 返回执行索引 } //7.菜单实现 /************************************************************************************** * FunctionName : App_ManageMenu() * Description : 管理菜单 * EntryParameter : None * ReturnValue : None **************************************************************************************/ void App_ManageMenu(void) { LCMDisplayStr(0, 0, " -= 管理系统 =- "); // 菜单标题显示 App_MenuSet(PAGE_DISP_NUM, M_MENU_NUM-PAGE_DISP_NUM+1); // 页显示3项,7个菜单项5页显示 App_MenuDisplay(MMenu, MenuPrmt.PageNo, MenuPrmt.DispNum, MenuPrmt.Cursor); // 显示菜单项 if (SysPrmt.KeyValue != KV_NO) // 有按键 { if (App_MenuMove(SysPrmt.KeyValue) == 0x00) // 菜单移动 { LCMClearScreen(LCM_WHITE); // 清屏 MMenu[MenuPrmt.Index].ItemHook(); // 执行相应项 } SysPrmt.KeyValue = KEY_NO; // 清除按键值 } }