为了方便使用,配合着Mz_MenuGUI代码提供了一份参考的响应控制代码,用户可以参照它的架构编写自己需要的控制代码。
当然,菜单的使用一般离不开键盘,在这里就使用了键盘扫描程序,但仅供参考,用户可以根据自己的情况编写合适的键盘扫描程序,并定义合适的键值作为菜单响应控制的控制键。
首先,菜单响应控制代码需要定义几个变量,如下:

上面定义的变量当中,有几个是用于暂存菜单组资源中的一些数据的,比如Item_Num、PageItem_Num等,其实在前面介绍的菜单显示控制的代码(Menu_GUI.c)当中已有定义了,这里再定义实际上是为多级菜单的使用而做的;因为在Menu_GUI.c当中定义的变量只能供当前选用的菜单组使用,如有多级菜单时,相互之间有层层的调用关系,单靠其中的变量是无法得知全部的菜单组资源的参数的。由此,建议每个菜单界面都应定义上述的变量,以供当前的菜单响应控制使用。
Exit_flag变量为循环退出标识,将在菜单响应控制的循环当中控制着是否继续下去,该变量被设置为0时,表示要退出当前的菜单。当然,如用户的菜单只有一层,而且始终在使用该菜单的话,可以不使用这个变量,直接在菜单响应控制的循环当中用1替代它即可。
菜单响应控制代码当中要使用到一些函数,所以在其前面需对一些外部头文件进行包含声明。如下:

Key.h是键盘扫描程序的头文件,这里不作说明。LCD_Dis.h为通用版的LCD驱动程序的用户接口程序头文件,可视情况而选择是否使用它(至少在用户的菜单响应控制代码当中是可以选择的)。
菜单响应控制的参考代码如下:


Key_Initial()是键盘扫描程序初始化函数,用户可根据自己的键盘扫描程序来修改这块的代码,而如果在之前已经进行过键盘扫描的初始化,则此处没有必要再重新初始化;比如在一个二级的菜单响应控制代码当中,它是由上一级的菜单响应控制代码响应操作而进入的,这时就无需再初始化扫键了。
LCD_Initil函数的调用也如此,如果是在二级菜单的响应控制代码中的话,是无需进行第二次初始化的。
接下来,调用Menu_GUI.c中的函数来初始化变量Item_Num和PageItem_Num的数值,注意,在调用相关的菜单GUI显示控制函数时,都要传递当前选择的菜单组资源到调用的函数当中的。有些编译器对数据的类型定义要求较严,这时在传递参数时需要对参数进行类型声明或强制转换。
每一个菜单组资源在使用时,在该菜单组的响应控制代码当中都要对其进行初始化,也就是调用Initial_Menu函数。
从前面的代码中可以看出,这份示例的菜单响应控制代码使用的菜单组资源是Menu_List01,它的定义在前面已经介绍过了。
while(Exit_flag)定义了菜单响应控制的循环,标志变量Exit_flag决定着这个循环是否继续下去。
Key_Get()函数可以获取到当前有效的按键值,当然,用户使用自己定义的键盘扫描程序时,应视自己的代码而定,反正只要能够获取到有效的按键值就可以了。获取的键值存放于uiKey变量当中;需要注意的是,在没有键按下时,获取键值的函数应返回0或其它的数值以区别有效的键值。
在上面的代码当中,当有效的按键按下时,uiKey的值为非零,这时会进行一个Switch的分支判断,以响应不同的按键。在代码当中,定义了uiKey的键值为1、2、3时的按键含意,也就是按键的作用;键值1为菜单项向上移动,键值2为菜单项向下移动,键值3为确定键,而在代码当中,有一段屏蔽掉的代码,为退出键的定义的,定义的键值为4。
当键值为1时,会调整当前活动的菜单项,并置标志变量Update_flag为1,让程序在循环当中刷新显示的菜单。
键值为2时,也调整当前活动的菜单项,当然是向下调整了,同时置标志变量Updage_flag为1,以控制刷新显示的菜单。
键值为3时,为确定键按下,置Enter_flag为1,在后面的代码当中会进行相对应的菜单项响应操作分支。
当键值分支处理代码执行结束后,循环当中会判断当前的显示是否需要刷新,即判断Update_flag的值,如果需要刷新,则调用UpDate_Menu函数。
随后的代码中,判断Enter_flag即确定按键是否按下,如按下,则进入菜单响应控制的分支处理;在switch分支中,根据Active_Index的值判断当前处于选择状态的菜单项是哪一个,然后进行分支处理,也就是每个case分支对应一个菜单项的响应,这里用户可以根据自己的需要进行代码的编写;例如在上面的代码当中就有一段屏蔽的代码,其响应第一项菜单项,调用了一个Show_DemoTask函数进入了一个显示界面(具体显示什么无所谓了,仅供参考),从该函数退出后,需要调用一个Redraw_Menu函数,重绘当前的菜单显示,然后置显示刷新标识Update_flag为1,在下一次循环中完成刷新显示。
每次循环里,都调用一个键盘扫描的函数:KeyScan_Service(),其实可以根据用户自己的键盘扫描程序架构而定的,这里仅供参考而已。
4.3.2. 订制一个有二级菜单的工程
先简单介绍一下这个有二级菜单的工程的一些要求,如下:
要求一级菜单有五项菜单项,分别为:
- 绘点
- 绘直线
- 绘矩形
- 字符演示
- 帮助
而字符演示这项的菜单响应有二级的菜单,即要求选择该项菜单项时,按下确定按键时会调出二级菜单,二级菜单要求有以下几项:
- 单个西文字符
- 西文字符串
- 中文字符
- 返回上一级
而在一级菜单的菜单项响应时,绘点这项就会在屏幕上绘制一个点,绘直线就在屏上绘制直线,基本上跟菜单中文字是意思相同的,只有“字符演示”这一项是展开二级菜单的;类似,在二级菜单当中,每一项的响应也是与其名字意义相同。
而设定以上的菜单项中的文字都是16*16点阵的汉字,而且事选都取好了字模放置在自定义的汉字库当中,并且都在Font_Set函数当中修改好了相关的配置;而定义好的汉字在字库中的序号分别为:
“绘点直线矩形字符演示帮助单个西文串中返回上一级”这些字符的序号从0~22依次排列;而字库的类型序号为3。
接下来就可以进行菜单系统的设计了,首先对于Menu_GUI的源码,只需要修改一部分的内容就可以了,也就是菜单资源的定义,即Menu_Resource.c中的定义。
修改的代码如下:

然后在Menu_GUI.h文件当中,添加定义的菜单组资源数组的声明,如下:
![]()
随后可以编写响应菜单项的功能函数,其实在这里也就是一些显示的演示程序,没有太多实际的意义,仅供参考,用户根据自己设计的需要来自行设计。
一级菜单的各项菜单项响应函数大概如下:
“绘点”菜单项,对应一绘点的演示界面,代码如下:

“绘直线”菜单项对应的函数代码如下:

“绘矩形”菜单项对应的函数源代码如下:

“帮助”菜单项的响应函数里将显示一串字符串,源代码如下:

“字符演示”的菜单项将来打开二级菜单,所以暂时将该菜单项的响应函数放置到后面,先将二级菜单当的各项菜单项对应的功能演示函数介绍。
二级菜单中,“单个西文字符”菜单项的响应函数定义为:Show_CharTest(),而菜单项“西文字符串”的响应函数定义为:Show_StringTest(),“中文字符”菜单项的响应函数定义为:Show_ChTest()。以上几个函数就不作详细的介绍了,而菜单项“返回上一级”的响应时无需调用函数那么复杂,可以在其的分支当中将菜单循环标志变量置为0即可实现。下面看一下在这个二级菜单的响应控制代码,也就是一级菜单中的菜单项“字符演示”所对应的响应函数:



然后再来看看一级菜单的源代码;在此一级菜单直接在main函数中循环响应,仅供参考,如下:



到这里,基本上就完成了在Mz_MenuGUI的基础之上搭建一个具有二级菜单的程序框架;其实介绍它的目的在于分绍一种根据显示界面而定下程序框架的编程方法,并非在于手把手的教读者去设计一个这样的程序,这点希望读者明白,重要的是编程的思想不在于步骤。
此外,笔者所附带着本书提供的例程当中,也许会与书上的描述有些许出入,毕竟有些代码是应用到以后,慢慢的进行完善和丰富,这点请各位见谅。


