在单片机中如果需要一个可以便于维护的菜单程序,那么设计一个便于封装的菜单数据结构就是必不可少的了。
最近观看B站UP主有手也不会发布的视频后,发现其写的菜单数据结构尤为好用,这里用于记录,有误之处还望大家指正!
按键采用Multibutton开源框架有兴趣可去GitHub上搜索,也可私信我,我发源码。

struct MenuItem
{unsigned char menu_cnt;             //当前菜单项目总数unsigned char * display_str;        //当前菜单要显示的字符void (*subs)();                     //选择某一菜单后要显示的功能函数struct MenuItem *children_menus;    //当前项目的子菜单struct MenuItem *parent_menus;      //当前项目的父菜单
};

从头到尾依次是:本级菜单所拥有的项目总数,当前项目所需要显示的菜单信息,所需要执行对应的菜单项目的回调函数,当前菜单的子菜单也就是下一级菜单,当前菜单的父菜单也就是上一级菜单。

在这本例移植中我是用了OLED12864进行显示
菜单数据,在此例子中共有两级菜单,每级菜单有三个项目

struct MenuItem parent_menu[] = {{3, (unsigned char *) "meat", NULL, NULL, NULL},
{3, (unsigned char *) "vegetable", NULL, NULL, NULL},
{3, (unsigned char *) "drinks", NULL, NULL, NULL},
};struct MenuItem childeren_menu1[] = {{3, (unsigned char *) "pork", fun1, NULL, parent_menu},
{3, (unsigned char *) "beef", fun2, NULL, parent_menu},
{3, (unsigned char *) "mutton", fun3, NULL, parent_menu},
};struct MenuItem childeren_menu2[] = {{3, (unsigned char *) "cabbage", fun4, NULL, parent_menu},
{3, (unsigned char *) "tomato", fun5, NULL, parent_menu},
{3, (unsigned char *) "potato", fun6, NULL, parent_menu},
};struct MenuItem childeren_menu3[] = {{3, (unsigned char *) "milk", fun7, NULL, parent_menu},
{3, (unsigned char *) "cola", fun8, NULL, parent_menu},
{3, (unsigned char *) "orange juice", fun9, NULL, parent_menu},
};

菜单显示函数

select_menu          //此变量是菜单结构体指针
select_item_num     //此变量是记录当前要显示本级菜单的第几个项目
void menu_display(void)
{unsigned char i;OLED_SetScreen(0);//清除OLED的缓存,即清屏for (i = 0;i < select_menu->menu_cnt;i++) {OLED_ShowString(32, i*12, (select_menu+i)->display_str, FONT_SIZE);//OLED显示对应的菜单项目名字信息if (i == select_item_num) OLED_ShowString(16, i*12, "->", FONT_SIZE);//如果是对应的项目则显示}OLED_RefreshGram();//将数据写入OLED中并显示
}//主循环中放入如下
//allow_switch表示是否允许切换 while(1){if (allow_switch) {allow_switch = 0;menu_display();}}

按键1单击表示本级菜单向下移动,双击表示返回上一级菜单
按键2单击表示本级菜单向上移动,双击表示进入下一级菜单

按键1处理回调函数

//recode变量可忽略,用于我自己的调试
void button1_callback_fun(void *btn, uint8_t event)
{unsigned char i;if ((event & SINGLE_CLICK) == SINGLE_CLICK) {//单击LED1_TOGGLE;//LED1翻转,用于调试时便于观察allow_switch = 1;//允许切换select_item_num++;//显示项目往下移if (select_item_num >= select_menu->menu_cnt) select_item_num = 0;//如果大于最大的显示项目回到第一个显示项目} else if ((event & DOUBLE_CLICK) == DOUBLE_CLICK) {//双击LED2_TOGGLE;//LED2翻转,用于调试时便于观察for (i = 0;i < select_menu->menu_cnt;i++) {//遍历是本级菜单哪一个项目要进入上一级菜单if (i == select_item_num) {//找到要进入上一级菜单的项目allow_switch = 1;//允许切换if ((select_menu->parent_menus != NULL) && (recode != 1)) {//上一级菜单是否为空select_menu = (select_menu+select_item_num)->parent_menus;//将菜单指针定位到上一级菜单select_item_num = 0;//回到上一级菜单从第一个项目开始}else if (recode == 1) {//可忽略recode = 0;}}}delay_ms(500);}}

按键2处理回调函数

void button2_callback_fun(void *btn, uint8_t event)
{unsigned char i;if ((event & SINGLE_CLICK) == SINGLE_CLICK) {//单击LED2_TOGGLE;//LED2翻转,用于调试时便于观察allow_switch = 1;//允许切换select_item_num--;//菜单往上移if (select_item_num < 0) select_item_num = select_menu->menu_cnt-1;//如果回到第一个项目仍然需要往上移,则回到最后一个项目} else if ((event & DOUBLE_CLICK) == DOUBLE_CLICK) {//双击LED3_TOGGLE;//LED3翻转,用于调试时便于观察for (i = 0;i < select_menu->menu_cnt;i++) {//遍历是本级菜单哪一个项目要进入下一级菜单if (i == select_item_num) {//找到要进入下一级菜单的项目allow_switch = 1;//允许切换if (select_menu->children_menus != NULL) select_menu = (select_menu+select_item_num)->children_menus;//下一级菜单是否为空else if (select_menu->subs != NULL) (select_menu+select_item_num)->subs();//如果回调函数不为空则执行对应的回调函数select_item_num = 0;//显示第一个项目}}delay_ms(500);}
}

单片机菜单-菜单数据结构相关推荐

  1. php 可编辑菜单,菜单的添加编辑

    摘要: 上级菜单 菜单名称 排序 控制器 方法 菜单状态 保存 //加载layui的弹窗组件和form组件 layui.use(['layer','form'],function(){ var for ...

  2. 如何动态添加菜单/菜单项、子菜单、右键菜单

    有关菜单的操作主要用到 CMenu 类,当然也可用相应 API 函数, CMenu 类只是 MFC 对 API 中操作菜单的函数的封装而已. 不过能用类就尽量用类,类的组织方式好呗,代码看着也舒服. ...

  3. GUI菜单——菜单条、菜单、子条目之间关系

    菜单:注意区分三个概念:菜单条.菜单.菜单项 将菜单条添加到窗体,菜单条下面包括菜单,菜单下面可以使菜单或者菜单项 菜单项是最后一个.菜单后面有三角标示. 菜单条[文件] 子菜单--子条目 子条目 示 ...

  4. 基于CSS3飘带状3D菜单 菜单带小图标

    这次我们要来分享一款很特别的CSS3菜单,菜单的外观是飘带状的,并且每一个菜单项有一个精美的小图标,鼠标滑过菜单项时,菜单项就会向上凸起,像是飘带飘动一样,形成非常酷的3D视觉效果.这款CSS3飘带状 ...

  5. 基于jQuery的下拉菜单菜单【02】,诸位上眼!!!

    前言 接上次的话题,仍然是团队近期将会有大变化,最近确实有点蛋疼,对以后的规划神马的乱成一团,晚上也不想学习神马的了,有时候就什么都不做发现一晚上就莫名其妙的过去了...... 但是上班时候不行,没事 ...

  6. GTA5内置html菜单源码,【GTA5线上1.46版本免费内置菜单菜单】【5款目前最新可用的内置菜单可供选择】刷钱、套模型、无敌、传送...

    功能上有线上刷钱,给其他玩家套模型 ,无敌 传送等等 首先先回答大家几个关于内置菜单的问题 1.内置菜单会封号嘛? 回答:外置菜单也会有几率封号,我只能说是挂都会有封号的几率,用内置就像抽烟的人对比不 ...

  7. android 菜单隐藏了,隐藏一些导航菜单菜单项 – Android

    我有导航抽屉.当一些事件被调用时,我想从用户隐藏我的一个导航菜单项.我能做到吗 protected void onCreate(Bundle savedInstanceState) { super.o ...

  8. 使用window.createPopup创建无限级跨帧下拉菜单

    我的BLOG搬家到自己的站点了 站点链接 RSS   先帖样子      使用层或者其他技术所实现的JS菜单不能解决的问题就是这些菜单不能跨帧,也就是说在Frame之间的时候无可奈何,所幸的是IE5+ ...

  9. 微信自定义菜单java_使用Java语言开发微信公众平台(八)——自定义菜单功能

    随着上一篇文章的结束,我们已经实现了所有消息的类型的回复功能.今天,我们来学习更加高大上,也更加重要的自定义菜单功能. 一.了解自定义菜单 自定义菜单是微信公众平台最常用也是最重要的功能之一.根据微信 ...

最新文章

  1. PCA中transform等scikit-learn中系列API用法
  2. rabbitmq 启动报错 Failed to get nic info
  3. 【Linux】34. shell脚本判断当前年份是否正确
  4. Deep Neural Networks的Tricks
  5. php数组循环0到32,通过数组php循环
  6. 笑话(15) 这是地球
  7. 搜索引擎怎么收集的那么多内容?
  8. Alter-有意思的小游戏
  9. python协同过滤电影推荐_基于协同过滤的电影推荐系统的设计与实现
  10. NEC电影服务器型号,NEC数字电影放映一体机NC2300S-A+详细信息_产品参数_价格_联系方式_DAV数字音视工程网...
  11. Elasticsearch的Watcher插件
  12. 作为一个部门 Leader,居然不如一个实习生
  13. 为什么很多人说Python简单呢?
  14. Keras过拟合相关解决办法
  15. JAVA链表中的回文链表结构
  16. 对于arm嵌入式系统的一点认识
  17. fastjason 0day 漏洞修复
  18. Win10系统中耳机插入前后面板均没有声音
  19. OMPL官方教程学习State Validity Checking
  20. 继电器模块的的使用方法、引脚说明、内部结构、接线说明(超通俗超详细看了就能给别人讲)

热门文章

  1. 2022年监理工程师质量/投资/进度控制考试每日一练及答案
  2. Nakamori Akina
  3. Entity Framework-Introduction
  4. 云电脑的四重守护,安全有谱
  5. matlab三相异步电动机,三相异步电动机仿真
  6. 杂项-公司:高通百科
  7. C# 网络斗地主源码开源
  8. 数据库-统计select的使用
  9. Vue在请求(axios)里面实现loading加载动画
  10. 2008-05-12 日志:佛祖诞生,惊天动地