推薦一個(gè)不錯(cuò)的應(yīng)用程序菜單框架
下面這個(gè)菜單框架也挺不錯(cuò)的,適合新手入門:
來源:http://www.80eboy.com/blog/menu_frame
相信很多攻城獅都用過液晶屏,想寫好一點(diǎn)的ui好像不太可能或且花費(fèi)很多時(shí)間,直接寫吧,感覺好像很零碎,coding都怕了。
下面介紹一個(gè)簡(jiǎn)單易用的菜單框架,你會(huì)發(fā)現(xiàn)它能做多層菜單而且結(jié)果清晰。
基本原理:

如上圖液晶顯示一屏我們定義為一個(gè)page,page中的項(xiàng)目定義為item;這樣page就是item的容器了。當(dāng)我們選中其中的一個(gè)item進(jìn)去后是不是又是一個(gè)page呢,如下圖。

這樣的話每一個(gè)item的下面都對(duì)應(yīng)一個(gè)page,這樣是不是就構(gòu)成一個(gè)多層的菜單了。

他們是什么關(guān)系呢?
一個(gè)page中有item,那么用結(jié)構(gòu)體就可以實(shí)現(xiàn)啦;item下面又有page,那么在item中加一個(gè)page的指針指向item對(duì)應(yīng)的page頁。
前面都是從上到下的,那么怎么返回呢?
觀察發(fā)現(xiàn)返回就是子page返回父page,這樣在page結(jié)構(gòu)體中假如一項(xiàng)父page的指針不就ok了。
具體實(shí)現(xiàn)請(qǐng)看源文件。
左右滑動(dòng)查看全部代碼>>>
/******************************************************************************************************/
//主菜單
//定義Item項(xiàng)?????????????//顯示方式&序號(hào)??項(xiàng)目的名字????項(xiàng)目指向的頁(Page)
const?struct?Item?main_item[]={?0x00,?"信息",???&SMS_Page,
????????0x01,?"設(shè)置",???&Setting_Page,
????????0x02,?"版本",???&Version_Page,
????????0x03,?"時(shí)間",???&Time_Page,
????????0x04,?"狀態(tài)",???0,
????????0x05,?"報(bào)警",???0,
????????0x06,?"飛信",???0,
????????0x07,?"問答",???0
};
//定義一個(gè)Page????????父頁?該頁的回調(diào)函數(shù)?該頁的項(xiàng)??????????項(xiàng)的個(gè)數(shù)????
const?struct?PAGE?mainPage={0,mainPageCallBack,main_item,sizeof(main_item)/sizeof(struct?Item)};
/*********************************************************************************************************/
const?struct?PAGE?Version_Page={&mainPage,Version_CallBack,0,0};
/***************************************************************************************************************/
//定義Item項(xiàng)??????????????//顯示方式&序號(hào)????項(xiàng)目的名字??????項(xiàng)目指向的頁(Page)
const?struct?Item?Setting_item[]={?0x10,?"?00.設(shè)0",???0,
?????????0x11,?"?01.設(shè)1",???0,
?????????0x12,?"?02.設(shè)2",???0,
?????????0x13,?"?03.設(shè)3",???0,
?????????0x14,?"?04.設(shè)4",???0,
?????????0x15,?"?05.設(shè)5",???0,
?????????0x16,?"?06.設(shè)6?你好",??0,
?????????0x17,?"?07.設(shè)7",???0,
?????????0x18,?"?08.設(shè)8",???0,
?????????0x19,?"?09.設(shè)9",???0,
?????????0x1A,?"?10.設(shè)10",???0
?????????};
const?struct?PAGE?Setting_Page={&mainPage,Setting_CallBack,Setting_item,sizeof(Setting_item)/sizeof(struct?Item)};
/***************************************************************************************************************/
const?struct?PAGE?Time_Page={&mainPage,Time_CallBack,0,0};
/***************************************************************************************************************/
//定義Item項(xiàng)??????????????//顯示方式&序號(hào)????項(xiàng)目的名字??????項(xiàng)目指向的頁(Page)
const?struct?Item?SMS_item[]={?
?????????0x10,?"?00.",???&SMS_Text_Page,
?????????0x11,?"?01.",???&SMS_Text_Page,
?????????0x12,?"?02.",???&SMS_Text_Page,
?????????0x13,?"?03.",???&SMS_Text_Page,
?????????0x14,?"?04.",???&SMS_Text_Page,
?????????0x15,?"?05.",???&SMS_Text_Page,
?????????0x16,?"?06.",???&SMS_Text_Page,
?????????0x17,?"?07.",???&SMS_Text_Page,
?????????0x18,?"?08.",???&SMS_Text_Page,
?????????0x19,?"?09.",???&SMS_Text_Page,
?????????0x1A,?"?10.",???&SMS_Text_Page
?????????};
const?struct?PAGE?SMS_Page={&mainPage,SMS_CallBack,SMS_item,sizeof(Setting_item)/sizeof(struct?Item)};
Menu.h:
左右滑動(dòng)查看全部代碼>>>
#ifndef?_Menu_H_BAB
#define?_Menu_H_BAB
#include?"stm32f10x.h"
#include?"LCD.h"
#include?"Key.h"
#define?KEY_Special??255?///<這個(gè)保留用于特別事件
//菜單調(diào)試,在調(diào)試時(shí)最好定義,可以幫助發(fā)現(xiàn)問題;當(dāng)發(fā)布時(shí)把其置為0可以加快速度
#define?MENU_DEBUG?1
void?Menu_Show(void);
struct?PAGE
{
?const?struct?PAGE?*pParent;
?void?(*Function)(u8?key);
?const?struct?Item?*pItem;
?const?u8?ItemNum;
};
struct?Item
{
?/**
?高4位作為特殊用途(bit4=1表示列表顯示否則兩列顯示),低4位用于標(biāo)記Item的序號(hào)??\n
?如果為列表模式時(shí)*pText的格式為:" xx.string",最前面保留一個(gè)空格用于個(gè)光標(biāo)(>)使用,xx.為兩位序號(hào)不要"."一定要有,string是要顯示的文字,最多能顯示6個(gè)漢字??\n
?如果是兩列顯示則pText,即為要顯示的文本(最多2個(gè)漢字)
?*/
?const?u8?TypeAndIndex;?
?const?u8?*pText;
?const?struct?PAGE?*pChildrenPage;
};
extern?const?struct?PAGE?*pPage;
void?SetMainPage(const?struct?PAGE?*pMainPage);
void?ShowMenu(const?struct?PAGE?*pPage);
void?ShowPage(const?struct?PAGE?*pPage);
void?ShowParentPage(void);
void?ShowItemPage(void);
void?SelPageItem(u8?ItemIndex);
u8?Menu_GetSelItem(void);
void?GetShowLst(u8?*pOutMin,u8?*pOutMax);
void?KeySelItem(u8?key);
#endif?
Menu.c:
左右滑動(dòng)查看全部代碼>>>
#include?"Menu.h"
//保存選中的菜單項(xiàng)變量
static?u8?SelItem=0;
/**
用于當(dāng)前LCD列表中顯示著哪幾項(xiàng)
高4位:最大序號(hào)
低4為:最小序號(hào)
*/
static?u8?ListShow=0x00;
const?struct?PAGE?*pPage;
void?SelItemOfList(u8?index);
void?SetMainPage(const?struct?PAGE?*pMainPage)
{
?pPage=pMainPage;
}
/**
獲得當(dāng)前選中的菜單項(xiàng)
@return?返回菜單序號(hào)
*/
u8?Menu_GetSelItem(void)
{
?return?SelItem;
}
/**
獲取當(dāng)前顯示列表的范圍
@param?pOutMin?當(dāng)前顯示的最小序號(hào)
@param?pOutMax?當(dāng)前顯示的最大序號(hào)
*/
void?GetShowLst(u8?*pOutMin,u8?*pOutMax)
{
?*pOutMin=ListShow&0x0f;?
?*pOutMax=ListShow>>4;
}
void?ShowList(u8?min,u8?max)
{
?u8?i=0,index=0;
?#if?MENU_DEBUG
??if(max-min>3)
??{
???Lcd_Clr_Scr();
???LCD_Write_Str(0,0,"err:ShowList>3");
???while?(1);
??}
??
??if?((pPage->pItem[0].TypeAndIndex?&?0x10)==0)///<如果是使用列表方式
??{
???
????Lcd_Clr_Scr();
????LCD_Write_Str(0,0,"不是列表類型不能不能列出");
????while?(1);?
??}
?#endif
?
?Lcd_Clr_Scr();
?for?(index=min;index<=max;index++)
?{
??LCD_Write_Str(i++,0,pPage->pItem[index].pText);
?}
?ListShow=(max<<4)|min;?///<記錄當(dāng)前顯示的Item
?
}
/**
頁顯示
1.當(dāng)這個(gè)頁有項(xiàng)目(Item)時(shí):顯示Item并同時(shí)選中Item 0???\n
2.沒有時(shí):會(huì)調(diào)用該P(yáng)age的回調(diào)函數(shù)并傳入KEY_Special?參數(shù)?\n
@param?pPage?指向一個(gè)page
*/
void?ShowPage(?const?struct?PAGE?*pPage)
{
?s8?i;
?///清屏
?Lcd_Clr_Scr();
???
?if(pPage->pItem==0)?
?{
??pPage->Function(KEY_Special);
??return;?///<如果沒有Item項(xiàng)則不顯示Item,直接返回
?}
??
?if?(pPage->pItem[0].TypeAndIndex?&?0x10)///<如果是使用列表方式
?{
??ShowList(0,3);
??SelItemOfList(0);
??pPage->Function(KEY_Special);
?}
?else
?{?
??///取出page中的Item并顯示
??for?(i=0;iItemNum;i++)
??{
???if?(i<4)
???{
????LCD_Write_Str(i,1,pPage->pItem[i].pText);
???}
???else
???{
????LCD_Write_Str(i-4,5,pPage->pItem[i].pText);
???}
???
??}
??SelPageItem(0);///<選中Item?0
??pPage->Function(KEY_Special);
?}
?
};
/**
顯示父頁(ParentPage)
*/
void?ShowParentPage(void)
{
?pPage=pPage->pParent;
?ShowPage(pPage);
}
/**
顯示項(xiàng)目(Item)下對(duì)應(yīng)的頁(Page)
*/
void?ShowItemPage(void)
{
?//如果該項(xiàng)下沒有頁,這警告或返回
?if?(pPage->pItem[Menu_GetSelItem()].pChildrenPage?==0)
?{
??#if?MENU_DEBUG
???Lcd_Clr_Scr();
???LCD_Write_Str(0,0,"該項(xiàng)下無顯示請(qǐng)修正");
???while?(1);
??#else
???return;
??#endif?
?}
?pPage=pPage->pItem[Menu_GetSelItem()].pChildrenPage;?//獲得菜單項(xiàng)(Item)對(duì)應(yīng)的page
?ShowPage(pPage);
}
/**
選擇page中的Item項(xiàng)
@param?ItemIndex?page中Item的索引號(hào)?0~7
*/
void?SelPageItem(u8?ItemIndex)
{
?///檢查是否有錯(cuò)誤調(diào)用
#if?MENU_DEBUG
?if?(ItemIndex>=8)
?{
??LCD_Write_Str(0,0,"設(shè)置菜單項(xiàng)溢出");
??return;
?}
#endif
///清除上次選中的
???if?(SelItem<4)
???{
??LCD_Write_Str(SelItem,0,"??");
??LCD_Write_Str(SelItem,3,"??");
?
???}
???else
???{
??LCD_Write_Str(SelItem-4,4,"??");
??LCD_Write_Str(SelItem-4,7,"??");
???}
///選中這次要選中的??
???if?(ItemIndex<4)
???{
??LCD_Write_Str(ItemIndex,0,"【");
??LCD_Write_Str(ItemIndex,3,"】");
??SelItem=ItemIndex;
???}
???else
???{
??LCD_Write_Str(ItemIndex-4,4,"【");
??LCD_Write_Str(ItemIndex-4,7,"】");
??SelItem=ItemIndex;
???}?
};
void?SelItemOfList(u8?index)
{
?u8?max;
?u8?min;
?
?max=ListShow>>4;
?min=ListShow&0x0f;
?
?if?(index>max)?///<超出最大當(dāng)前顯示的序號(hào)
?{
??
??LCD_Write_Str(Menu_GetSelItem()-min,0,"?");
??
??min+=1;
??max+=1;
??ShowList(min,max);
??ListShow=(max<<4)|min;
??
??LCD_Write_Str(index-min,0,">");
??
?}
?else?if(index>=min)///<在最小和最大序號(hào)之間
?{
??LCD_Write_Str(Menu_GetSelItem()-min,0,"?");
??LCD_Write_Str(index-min,0,">");
?}
?else?????///<低于最小當(dāng)前顯示最小序號(hào)
?{
??LCD_Write_Str(Menu_GetSelItem()-min,0,"?");
??
??min-=1;
??max-=1;
??ShowList(min,max);
??ListShow=(max<<4)|min;
??
??LCD_Write_Str(index-min,0,">");
?}
?SelItem=index;
}
void?KeySelItem(u8?key)
{
?s8?index;
?if?(pPage->pItem[0].TypeAndIndex?&?0x10)///<如果是使用列表方式
?{
??switch(key)
??{
???case?KEY_UP:
????index=Menu_GetSelItem()-1;
????if(index<0)?break;
????
????SelItemOfList(index);
????break;
???case?KEY_Down:
????index=Menu_GetSelItem()+1;
????if(index>(pPage->ItemNum-1))?break;;
????SelItemOfList(index);
????break;
??}
??return;
?}
?switch(key)
?{
??case?KEY_UP:
???index=Menu_GetSelItem()-1;
???if(index<0)?index=pPage->ItemNum-1;
???SelPageItem(index);
???break;
??case?KEY_Down:
???index=Menu_GetSelItem()+1;
???if(index>(pPage->ItemNum-1))?index=0;
???SelPageItem(index);
???break;
??case?KEY_Left:
??case?KEY_Right:?
???index=Menu_GetSelItem();
???if?(index<4)
???{
????if((index+4)>(pPage->ItemNum-1))?return;?//右沒有Item項(xiàng),無法選中右邊項(xiàng);所以返回
????index+=4;????????//右邊有Item時(shí)把index定位到右邊的Item
???}?
???else?????index-=4;??????//因?yàn)橛疫呌蠭tem項(xiàng)時(shí),左邊一定有Item項(xiàng);因?yàn)槭前错樞虬才诺?/span>
???SelPageItem(index);
???break;
?}
}
篇幅有限,MenuAPP代碼未貼出。
完整工程代碼獲取方式:
可在微信公眾號(hào)【技術(shù)讓夢(mèng)想更偉大】,點(diǎn)擊下方,在后臺(tái)回復(fù)關(guān)鍵字:Menu?,即可獲取。
???????????????? ?END ????????????????
關(guān)注我的微信公眾號(hào),回復(fù)“加群”按規(guī)則加入技術(shù)交流群。
點(diǎn)擊下面圖片,有星球具體介紹,新用戶有新人優(yōu)惠券,老用戶半價(jià)優(yōu)惠,期待大家一起學(xué)習(xí)一起進(jìn)步。
點(diǎn)擊“閱讀原文”查看更多分享,歡迎點(diǎn)分享、收藏、點(diǎn)贊、在看。
