需要创建一个菜单的结构体,以便建立链表

typedef struct menu {  //定义一个菜单uint8_t range_from,range_to; //当前显示的项开始及结束序号uint8_t itemCount;//项目总数uint8_t selected;//当前选择项char menuItems[SUBMENUS][17];//菜单项目struct menu *subMenus[SUBMENUS];//子菜单struct menu *parent;//上级菜单 ,如果是顶级则为nullint (*func[SUBMENUS])(void);//选择相应项按确定键后执行的函数float funcValue[SUBMENUS];uint32_t menuId[SUBMENUS];
}Menu;

创建一些基本的函数

/** 添加下级单项菜单函数* menu:        菜单指针* submenus:    下级单项菜单* index:       索引值* return:索引值 error:-1  */
int Menu_addItem(Menu *menu, Menu * subMenu, uint8_t index) {if (menu == NULL) {DEBUGOUT("menu is null");return -1;}if (index > menu->itemCount) {DEBUGOUT("index too big");return -2;}//menu的下级菜单索引值[i]为subMenumenu->subMenus[index] = subMenu; menu->menuId[index+1] = (menu->menuId[0] << 4) | (index + 1);subMenu->menuId[0] = menu->menuId[index+1];//subMenu的上级菜单为menusubMenu->parent = menu;//printf("menu->id=%02x, submenu->id=%02x\r\n", menu->menuId[0], subMenu->menuId[0]);return index;
}

这个函数是进行下级菜单的插入,进行菜单的深度插入。
同时,将下级菜单的父级菜单绑定到当前菜单上,这样使用返回的时候,可以跳转到本机菜单。

char Menu_addFunc(Menu * menu, int(*fun)(void), uint8_t index) {if (menu == NULL) {DEBUGOUT("menu is null");return 0;}if (index > menu->itemCount) {DEBUGOUT("index is too big");return 0;}if (fun == NULL) {DEBUGOUT("function is null");return 0;}//添加调用函数menu->func[index] = fun;menu->menuId[index+1] = (menu->menuId[0] << 4) | (index + 1);    return 1;
}

进行参数判断
把函数绑定到菜单的函数列表中

/** 返回上级菜单* * menu:        菜单指针*/
void Menu_return(Menu * menu) {if (menu == 0){DEBUGOUT("menu is null");return ;}// LCD清屏操作f_LCD_clear = SET;if (LCD_TaskFlag & TASK_SET) {LCD_TaskFlag &= ~TASK_SET;} else {//如果有上级菜单的话if (menu->parent) {currentMenu = menu->parent;}}
}

会去判断menu->parent是否存在,如果存在,则跳转到上级菜单。
返回上级菜单,从最低级菜单,一层层返回到第高级菜单上。
如果没有上级菜单,则不进行刷新界面。


/** 进入子菜单* menu:        菜单指针 * index:       子菜单索引* 如果存在函数,首先运行函数。*/
void Menu_enter(Menu * menu, uint16_t index) {// LCD清屏操作f_LCD_clear = SET;//索引值大于项目总数 且 不具有下级子菜单if (index >= menu->itemCount || (menu->subMenus[index] == NULL || menu->subMenus == NULL)) {//如果存在函数  执行函数if (menu->func != NULL && menu->func[index] != NULL) {LCD_TaskFlag |= TASK_SET;// 执行函数(*menu->func[index])();}} else {// 进入子菜单currentMenu = menu->subMenus[index];}
}

判断当前选中菜单是否大于总数 && 下级菜单列表是否为空 && 选中菜单项是否有下级菜单
如果不满足,则进入函数选择分支
判断当前选中函数列表是否为空 当前选中函数指针是否为空
如果有可执行函数,置函数标志位LCD_TaskFlag |= TASK_SET;
接下来直接执行函数(*menu->func[index])();
如果不满足上述条件,则说明有下级菜单。

进行显示部分说明

//LCD显示函数重定义
#define LCD_displayStr       my_LCD_Display_String
#define LCD_displayStrRev    my_LCD_Display_String_Reverse
#define LCD_displayChar      my_LCD_Display_Char
#define LCD_displayCharRev   my_LCD_Display_Char_Reverse
#define LCD_Clear            my_LCD_Display_Clear

这些函数在display.c中直接定义,如果需要在LCD屏幕上实现,则只需要实现这几个函数就可以


void my_LCD_Display_String(unsigned char x, unsigned char y, char *displayStr) {uint8_t col, len;for (col = 0;col < strlen(displayStr);col++) {LCD_Screen[x][y+col] = displayStr[col];}
}void my_LCD_Display_String_Reverse(unsigned char x, unsigned char y, char *displayStr) {uint8_t col, len;for (col = 0;col < strlen(displayStr);col++) {LCD_Screen[x][y+col] = displayStr[col];}
}
void my_LCD_Display_Clear(void) {uint8_t row;if (!f_LCD_clear) {return ;}for (row = 0;row < 4;row++) {my_LCD_Display_String(row, 0, MSG_LCD_NULL);}
}

声明一个数组LCD_Screen,用来存放需要显示的字符,共分为4行16列
显示时,显示LCD_Screen的数据即可。


#define FOREGROUND_WHITE    (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED)
#define BACKGROUND_WHITE    (BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_RED)#define normal_display(x, y) \do { \pos.X = 50+y;\pos.Y = 10+x;\SetConsoleCursorPosition(hOut, pos); \SetConsoleTextAttribute(hOut, BACKGROUND_WHITE);\} while (0)#define rev_display(x, y) \do { \pos.X = 50+y;\pos.Y = 10+x;\SetConsoleCursorPosition(hOut, pos); \SetConsoleTextAttribute(hOut, BACKGROUND_GREEN);\} while (0)void LCD_Dispaly(void) {uint8_t row = 0, col = 0;for (row = 0;row < 4;row++) {if (row != currentMenu->selected) {for (col = 0;col < 16;col++) {normal_display(row, col);dchar(LCD_Screen[row][col]);}} else {for (col = 0;col < 16;col++) {rev_display(row, col);dchar(LCD_Screen[row][col]);}}}
}

normal_display() 是进行正常显示
rev_display() 是进行反向显示
因为我是在上位机C语言环境下进行调试,所以这个是可以在控制台上输出正向和反向打印。

进行一些初始化

/** 以下程序,可以放置在本文件外部* 属于本菜单程序实例 *///一级菜单
Menu fMenu = {// form, to, count, selected0, 3, 4, 0, // items string{"1","2","3","4",},
};// 二级菜单
Menu Menu_Level = {// form, to, count, selected0, 2, 3, 0, // items string{"11","12","13",},
};Menu Menu_Temp = {// form, to, count, selected0, 0, 1, 0, // items string{"21",},
};
Menu Menu_Alarm = {// form, to, count, selected0, 1, 2, 0, // items string{"211","212",},
};//int LCD_displayLevelHigh(void) {//  char s[20];
//  sprintf(s, "   %.0f", LCD_DisplayTempValue);
//  LCD_displayStr(1, 0, s);
//}
#define GET_LCD_FUNC_NAME(name)    (LCD_display##name)#define LCD_CREATE_DISPLAY_FUNC(name, title, unit) \
static int LCD_display##name(void) { \char s[20]; \LCD_displayStr(0, 0, #title); \sprintf(s, "%.2f %s", LCD_DisplayTempValue, #unit); \LCD_displayStr(1, 3, s); \
}
LCD_CREATE_DISPLAY_FUNC(LevelHigh, level, mm);void menu_init(void) {Menu_addFunc(&Menu_Level, GET_LCD_FUNC_NAME(LevelHigh), 0);Menu_addItem(&fMenu, &Menu_Level, 0);Menu_addItem(&fMenu, &Menu_Temp, 1);Menu_addItem(&fMenu, &Menu_Alarm, 2);   currentMenu = &fMenu;
}

此部分主要是进行菜单的初始化和对第二级菜单的绑定
利用宏,进行方便的创建显示函数,和获取显示函数的名字
将显示函数绑定到指定的菜单项上
currentMenu = &fMenu; 将第一级菜单作为当前菜单进行显示。
currentMenu 是当前可以操作的菜单


#define TASK_SET        0x0001  // 设置界面
#define TASK_ROOT       0x0002  // 登陆用户状态 0:user 1:root
#define TASK_DFP        0x0004  // 显示界面状态(DFP:displayFirstPage) 0:首页 1:菜单项
#define TASK_GPRS       0x0008  // GPRS发送状态 0:不可以发送 1:可以发送
#define TASK_SW         0x0010  // 电磁阀开启状态:0:没有开启 1:开启
#define TASK_LOGIN      0x0020  // 登陆状态 0:未登录 1:已登录

需要有一些显示控制位,来表达当前显示任务处于什么样的显示阶段。

进行实验

**本代码是在win10上使用c-free5进行调试,可以正常执行,后续还会对这个代码进行修改和优化,如果看到有问题的地方,希望指出来,帮助改正 **

资源放在CSDN上了,由于资源分最低2分,所以就放了两分,如果没有分的同学,可以去百度云上下载。

CSDN链接
百度云链接
上:上翻页
下:下翻页
左:返回上级菜单或者退出函数显示
右:进入下级菜单或者进入函数显示

设计上可以参考 simple gui

LCD12864 菜单部分编写相关推荐

  1. 使用ie的菜单接口编写自己浏览器插件

    增加ie右键菜单reg文件内容 -------------------- Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER/Softwar ...

  2. cocoscreator游戏开发实战——动物餐厅——菜单代码编写(2)

    首先新建一个Food脚本,然后把他挂载到Food这个预制体上,目的远程加载图片.去显示菜单德图片. 使用的api cc.assetManager.loadRemote(info['URL'],func ...

  3. cocoscreator游戏开发实战——动物餐厅——菜单代码编写(1)

    这是项目结果图,我们这章节主要介绍怎么实现它. 首先:新建一个模块脚本,命名为config,然后在配置要求的菜单信息.  name:是物品名称, id:是数据索引 URL:是物品的云存储链接 del, ...

  4. Android — 长按ListView 利用上下文菜单(ActionMode) 进行批量事件处理

    好久没写博客拉``````` 近期最终略微闲一点了``````` 无聊拿手机清理短信.发现批量事件的处理还是挺管用的`````` 那么自己也来山寨一记看看效果吧````` 闲话少说,首先,我们来看下手 ...

  5. VC++动态创建和删除菜单(转)

    在应用程序中,往往要根据当前的操作来增加相应的菜单.动态增加菜单的方法有多 种,本文只讲述利用资源编辑器预创建菜单资源,然后在程序运行中动态加入(或删 除)到主菜单中去的方法. 一.用AppWizar ...

  6. html下拉折叠菜单,原生Js_实现简单的下拉折叠菜单(添加弹出动画效果)

    用javascript实现简单的下拉折叠菜单 Gary_js实现简单的下拉折叠菜单 *{margin:0px; padding:0px;} #div1 {width:200px; margin:0 a ...

  7. 在PyQt中构建 Python 菜单栏、菜单和工具栏

    摘要:菜单.工具栏和状态栏是大多数GUI 应用程序的常见且重要的图形组件.您可以使用它们为您的用户提供一种快速访问应用程序选项和功能的方法. 本文分享自华为云社区<Python 和 PyQt:创 ...

  8. 安卓学习笔记26:菜单

    文章目录 零.学习目标 一.菜单概述 二.选项菜单案例演示 (一)运行效果 (二)实现步骤 1.创建安卓应用[OptionsMenuDemo] 2.将背景图片拷贝到drawable目录 3.主布局资源 ...

  9. pyqt5 treeview鼠标右键菜单事件_【动手实践】使用 Vue 自定义指令实现右键菜单...

    本文来自于 神奇的程序员 前言 浏览器里右键时会有一个默认的菜单,在我的开源项目中正好有自定义右键菜单的需求,在npm库找了下与之相关的包,发现都是以组件形式实现的,感觉那种做法太过繁琐. 于是,我就 ...

最新文章

  1. 加速!上海要做人工智能产业“领头雁”
  2. Symfony2学习笔记之HTTP Cache
  3. 我的第一个ASP类(显示止一篇下一篇文章)
  4. 写了个Linux包过滤防火墙
  5. 类和对象——对象特性——this指针的用途
  6. 深度学习代码注解(一)—— mnistdeepauto
  7. Android studio 开发中 用git实现批量忽略特定文件的方法
  8. 工作区、暂存区、版本库、远程仓库
  9. JS键盘字母相应的keyCode值
  10. 【SSH】 之 Struts2
  11. 14的虚拟机可以用在15上面吗_【Linux虚拟机】在Windows上安装Linux虚拟机
  12. 自动驾驶 11-2: 激光雷达传感器模型和点云 LIDAR Sensor Models and Point Clouds
  13. ASCⅡ码与字符的相互转化
  14. word批量转pdf,word批量转pdf步骤
  15. msconfig蓝屏_电脑msconfig改动后蓝屏怎么修复
  16. 性能测试模型之曲线拐点模型——压力曲线分析图
  17. LLC谐振变换器原理及变频控制
  18. 阿里云DataWorks数据集成(DataX)架构实践分享
  19. 云安全将来时 | 云安全的发展与未来趋势
  20. base64编码转码

热门文章

  1. 金额数字转换(小写转大写)
  2. 可视化绘图技巧100篇分析篇(一)-数据降维NMDS分析(补充篇)
  3. 解决react项目启动报错:error Couldn't find a package.json
  4. 龚鹏:我是怎么从程序员成为全栈GEEK的
  5. 工信部等三部委:推进区块链等新一代信息技术在养老场景集成应用
  6. UE4 UMG多行文本
  7. css画心形原理,如何用 css 画一个心形
  8. 为什么YUV全为0的图像是绿色的
  9. 新手学习python零基础_一个零基础新手学习Python应该知道的学习步骤与规划
  10. 干货!如何快速拥有自己的商城APP