|
这个得从上一年我要做一个带有菜单的项目说起,一开始听说要做个带有菜单的项目,不知从何做起,在阿莫这看到了《一个占用内存极少的菜单系统的实现》,研究了这个菜单的代码结构并参照这个菜单的内核,自己写了个菜单代码。也就从这里开始,自己理解了菜单是一个怎样的东西。当我把这个写好的菜单用到我的系统上,我注意到了有几个地方要改进,第一:菜单的移植性,第二:菜单的修改维护,第三:菜单项目的扩展功能(使用灵活性)。
提示一下:其实我只是提出一些我个人的观点和学术上的建议,我们更多的是互相交流学习,取长补短,共同进步。
第一:菜单的移植性
_CONST_ KbdTabStruct KeyTab[]={
// |-----------> Index
// | Up
// | | Down
// | | | Left
// | | | | Right --->功能函数
// | | | | | |
{ 0, 1, 2, 3, 4,(*DispMenuTop)},// 待机画面
{ 1, 0, 0, 0, 0,(*DispMenuTopUp)},
{ 2, 0, 0, 0, 0,(*DispMenuTopDown)},
{ 3, 0, 0, 0, 0,(*DispMenuTopLeft)},
{ 4, 0, 0, 0, 0,(*DispMenuTopRight)},
{ 5, 6, 7, 8, 9,(*DispIcoMenuInit)}, //图标层菜单
{ 6, 0, 0, 0, 0,(*DispIcoMenuUp)}, //
{ 7, 0, 0, 0, 0,(*DispIcoMenuDown)}, //
{ 8, 0, 0, 0, 0,(*DispIcoMenuLeft)}, //
{ 9, 0, 0, 0, 0,(*DispIcoMenuRight)},//
{10,11,12,13,14,(*DispMenuFuncInit)}, //"功能"
{11, 0, 0, 0, 0,(*DispMenuFuncUp)}, //
{12, 0, 0, 0, 0,(*DispMenuFuncDown)}, //
{13, 0, 0, 0, 0,(*DispMenuFuncLeft)}, //
{14, 0, 0, 0, 0,(*DispMenuFuncRight)},//
{15,16,17,18,19,(*DispMenuParaInit)}, //"参数"
{16, 0, 0, 0, 0,(*DispMenuParaUp)}, //
{17, 0, 0, 0, 0,(*DispMenuParaDown)}, //
{18, 0, 0, 0, 0,(*DispMenuParaLeft)}, //
{19, 0, 0, 0, 0,(*DispMenuParaRight)},//
{20,21,22,23,24,(*DispMenuLanguageInit)}, //"语言"
{21, 0, 0, 0, 0,(*DispMenuLanguageUp)}, //
{22, 0, 0, 0, 0,(*DispMenuLanguageDown)}, //
{23, 0, 0, 0, 0,(*DispMenuLanguageLeft)}, //
{24, 0, 0, 0, 0,(*DispMenuLanguageRight)},//
{25,26,27,28,29,(*DispMenuMeasureInit)}, //"测量"
{26, 0, 0, 0, 0,(*DispMenuMeasureUp)}, //
{27, 0, 0, 0, 0,(*DispMenuMeasureDown)}, //
{28, 0, 0, 0, 0,(*DispMenuMeasureLeft)}, //
{29, 0, 0, 0, 0,(*DispMenuMeasureRight)},//
#ifdef DynamicBar
{30,31,32,33,34,(*DispMenuDataInit)}, //"Data"
{31, 0, 0, 0, 0,(*DispMenuDataUp)}, //
{32, 0, 0, 0, 0,(*DispMenuDataDown)}, //
{33, 0, 0, 0, 0,(*DispMenuDataLeft)}, //
{34, 0, 0, 0, 0,(*DispMenuDataRight)},//
#endif
};
这个是菜单的结构,在做程序的时间都一一定好那个项在那个位置,当移植到其它的项目上,这个菜单全部都得重做。
第二:菜单的修改维护
当菜单项要修改位置、菜单项功能和菜单扩展功能时,所需做的功夫比较大。当菜单项比较多,而且又有菜单扩展功能,修改起来有时很容易搞乱。
第三:菜单项目的扩展功能(使用灵活性)
举个例子:当前菜单项是“电机启动”窗口提示按某个键“启动电机”,当电机启动后菜单项中文显示为“电机停止” 窗口又提示按某个键“电机停止”。
再有就是同一个菜单项要负责多个扩展功能
举个例子:当前菜单项是“电机控制”再按确定后,弹出一个小窗口并列表显示数个电机的顺序,面板上的数字键都可单独控制一个确定的电机启动/运行。
要在这个菜单内核上实现这些功能的时候,就显示有些力不从心了。
/****************************************************************************************/
点击此处下载 ourdev_557291.rar(文件大小:3K) (原文件名:menu.rar)
这个代码是我参照《一个占用内存极少的菜单系统的实现》写的,在可移植性上我还是做了些改进,你留心一下会发现不同的菜单层UP与DOWN的代码是一样的,移植和维护都不用动这一部分的代码。这里只要就是菜单层之间的切换比较麻烦。
/*******************************************************************************************/
以下是我从项目里整理出来的原创菜单源码
我的特点是以菜单节点为对象而组建的一个菜单体,每层菜单最大支持99菜单项
//--------菜单节点结构体
typedef struct _MenuNode
{
unsigned int MenuNodeID;
unsigned char *MenuString;
unsigned char MenuStatus;
struct _MenuNode *First_Node;
struct _MenuNode *Last_Node;
struct _MenuNode *Prev_Node;
struct _MenuNode *Next_Node;
void(*Action)(unsigned char in);
}MenuNode;
//--------菜单链表
typedef struct _MenuList
{
struct _MenuNode *Point_Node[MenuTotalNode];
}MenuList;
根椐菜单的编码结构可以随意修改和添加菜单项目,
//--------当前菜单信息
MenuNode MenuNode1 ={1,"1",0,(void*)0,(void*)0,(void*)0,(void*)0,MenuNode1Action};
MenuNode MenuNode2 ={2,"2",0,(void*)0,(void*)0,(void*)0,(void*)0,MenuNode2Action};
MenuNode MenuNode101={101,"101",0,(void*)0,(void*)0,(void*)0,(void*)0,MenuNode101Action};
MenuNode MenuNode102={102,"102",0,(void*)0,(void*)0,(void*)0,(void*)0,MenuNode102Action};
MenuNode MenuNode103={103,"103",0,(void*)0,(void*)0,(void*)0,(void*)0,MenuNode103Action};
MenuNode MenuNode201={201,"201",0,(void*)0,(void*)0,(void*)0,(void*)0,MenuNode201Action};
菜单的链表结构在菜单初始化完成
//--------菜单初始化
void MenuListInit(void)
{
unsigned char i;
MenuNode *InitMenuNode;
CurrentMenuNode=&MenuNode1;
MenuTotalList.Point_Node[0]=&MenuNode1;
MenuTotalList.Point_Node[1]=&MenuNode2;
MenuTotalList.Point_Node[2]=&MenuNode101;
MenuTotalList.Point_Node[3]=&MenuNode102;
MenuTotalList.Point_Node[4]=&MenuNode103;
MenuTotalList.Point_Node[5]=&MenuNode201;
for(i=0;i<MenuTotalNode;i++)
{
InitMenuNode=MenuTotalList.Point_Node;
(*InitMenuNode).First_Node=SearchMenuNode((*InitMenuNode).MenuNodeID,firstnode);
(*InitMenuNode).Last_Node =SearchMenuNode((*InitMenuNode).MenuNodeID,lastnode);
(*InitMenuNode).Prev_Node =SearchMenuNode((*InitMenuNode).MenuNodeID,prevnode);
(*InitMenuNode).Next_Node =SearchMenuNode((*InitMenuNode).MenuNodeID,nextnode);
}
}
可以灵活添加和修改扩展功能
void MenuNode101Action(unsigned char key)
{
Lcd_Clr();
switch(key)
{
case key0code:
case key1code:
case key2code:
case key3code:
case key4code:
case key5code:
case key6code:
case key7code:
case key8code:
case key9code:if(num101<8){tab101[num101]=key;num101++;}break;
case key10code:if(num101>0){num101--;tab101[num101]=0;}break;
default:break;
}
LCD_Write_String(0,0,"101请输入:");
LCD_Write_Number(0,1,tab101,num101);
}
菜单内核调度代码在移植时不用修改
//--------菜单显示
void MenuShow(void)
{
unsigned char i;
static MenuNode *ShowMenuNode;
switch(CurrentMenuStatus)
{
case menufunc:
Menu_LCD_Clr();
ShowMenuNode=SearchSomeOneMenuNode((*CurrentMenuNode).MenuNodeID-CurrentMenuCur);
Menu_LCD_Write_String(0,CurrentMenuCur,"->");
for(i=0;i<MaxScreenSize;i++)
{
Menu_LCD_Write_String(2,i,(*ShowMenuNode).MenuString);
if((*ShowMenuNode).Last_Node!=NULL)
{
ShowMenuNode=(*ShowMenuNode).Last_Node;
}
else
break;
}
break;
case numberfunc:
break;
default:break;
}
}
//--------菜单索引操作
void MenuFunctionKey(unsigned char key)
{
MenuIntDisable();
switch(key)
{
case Key_First:
if((*CurrentMenuNode).First_Node!=NULL)
{
CurrentMenuNode=(*CurrentMenuNode).First_Node;
if(CurrentMenuCur>0)
CurrentMenuCur--;
}
break;
case Key_Last:
if((*CurrentMenuNode).Last_Node!=NULL)
{
CurrentMenuNode=(*CurrentMenuNode).Last_Node;
if(CurrentMenuCur<(MaxScreenSize-1))
CurrentMenuCur++;
}
break;
case Key_Prev:
if((*CurrentMenuNode).Prev_Node!=NULL)
{
CurrentMenuNode=(*CurrentMenuNode).Prev_Node;
MenuDeep--;
CurrentMenuCur=MenuCurStack[MenuDeep];
}
break;
case Key_Next:
if((*CurrentMenuNode).Next_Node!=NULL)
{
CurrentMenuNode=(*CurrentMenuNode).Next_Node;
MenuCurStack[MenuDeep]=CurrentMenuCur;
CurrentMenuCur=0;
MenuDeep++;
}
break;
default:break;
}
MenuIntEnable();
}
//--------菜单扩展操作功能
void (*MenuNodeAction)(unsigned char key);
//--------菜单按键功能, 扩展功能
void MenuNumberKey(unsigned char key)
{
MenuIntDisable();
MenuNodeAction=(*CurrentMenuNode).Action;
MenuIntEnable();
(*MenuNodeAction)(key);
}
点击此处下载 ourdev_557288.rar(文件大小:10K) (原文件名:menusource.rar)
说明:这个菜单代码是在老板要求做一个小的手持终端设备,在我对菜单原有的理解和结合新的需要而设计出来的,也是从少少的几代码一步一步添加和调试完善起来的,我这次从这个项目里整理这个菜单代码出来,功能不是很完善,但我觉得这个菜单的内核结构是比较好的。
一些想法和建议:我希望朋友们看下我这个代码,有些不完善的地方可以提出来并自行修改用在你的项目上,并且能在这里跟贴,也尽你的一份责任,让同行兄弟们学习学习。还有就是,我现在不做技术了,有空也会搞下这个,但是少了,我知道阿莫这里平时是很多高手出没的,我希望有些热心的朋友继续完善这个菜单,也或你了解这个内核的结构,会有更好更有创意的想法并结合你自己的长处开发出一个更加好的GUI。当然啦,能开源给兄弟们学习使用,那就最好,兄弟们都会感谢你为我们辛勤而又无私的付出。
谢谢各位的支持!十分感谢!
有什么问题可以随时联系我,我的QQ是:178122887,电话:13570402599 |
阿莫论坛20周年了!感谢大家的支持与爱护!!
该献的血还是要献的。你不献他不献。难道让我去献? --- 出自坛友:lovejp1981
|