求助菜单设计

2019-03-24 17:48发布

在网上搜索了一段时间的菜单设计,看的稀里糊涂,没找到一个相对完整的,哪位坛友能给个相对完整的例子或清晰明了的思路,不胜感激! 此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
13条回答
硕果累累
2019-03-25 04:30
我也和你有同样的感受,我也在学习菜单设计,也找了许多这方面的程序来学习,可是一直都是稀里糊涂的,看不懂,不知道编程的思路。我现在用的处理器是STM32,下面是我找到的程序,我也学习了,但是还是看不懂,不会写。
这个程序是我认为功能能够实现,能够在我的板子上面跑起来,函数清晰。
********感谢原作者的分享***********************
  1. #include "menu.h"
  2. #include "oled.h"
  3. #include "key.h"
  4. #include "delay.h"
  5. #include "text.h"
  6. #include "fontupd.h"

  7. /*菜单结构定义*/
  8. struct Option
  9. {
  10.     unsigned char KeyLevel;       //菜单选项所属菜单表号
  11.     unsigned char EnterIndex;     //选项进入索引号
  12.     unsigned char CancelIndex;    //选项退出索引号
  13.     unsigned char *KeyWord;       //菜单选项文字描述指针
  14.     unsigned char WordMete;       //菜单选项描述文字字节数
  15. };

  16. /**
  17. *        具体菜单选项定义,定义一个结构数组
  18. *        存储在编码区,节省内存RAM
  19. **/
  20. struct Option sOption[OPTIONMETE] =
  21. {
  22. /*菜单表号 进入索引 退出索引 菜单选项文字 菜单选项文字字节数*/
  23.         {0, OPTIONMETE - 1, 0, "1.亮度调节",   10},//0
  24.         {0, 6,                                    1,    "2.时间设置",   10},//1
  25.         {0, OPTIONMETE - 1, 2, "3.系统检测",   10},//2
  26.         {0, OPTIONMETE - 1, 3, "4.修改密码",   10},//3
  27.         {0, OPTIONMETE - 1, 4, "5.帮助说明",   10},//4
  28.         {0, OPTIONMETE - 1, 5, "6.系统信息",   12},//5
  29.         {1, OPTIONMETE - 1, 1, "1.时钟设置",   10},//6
  30.         {1, OPTIONMETE - 1, 1, "2.日期设置",   10},//7
  31. };

  32. /*菜单表分类数组*/
  33. unsigned char Level[MENULEVEL][3] =
  34. {
  35. /*每层表单对应的开始索引  结束索引  选项数目*/
  36.     {0, 5, 6},
  37.     {6, 7, 2},
  38. };

  39. /*菜单索引定义*/
  40. unsigned char FirstLineDisIndex = 0;    //屏幕第一行显示的索引号
  41. unsigned char SelectLine_L = 1;                    //原来选中行
  42. unsigned char SelectLine = 1;                      //当前选择的行
  43. unsigned char SelectIndex = 0;                     //当前选定行对应的索引号
  44. unsigned char LastIndex = 0;                      //进入功能函数前的索引号,判断具体功能使用

  45. /**
  46.   * @name        void Select_Line(unsigned char line, unsigned char clear)
  47.   * @brief  选中行反白显示
  48.   * @param        line:选中行                clear:1,选中行清除反白 0,选中行反白显示
  49.   * @retval        none
  50.   */
  51. void Select_Line(unsigned char line, unsigned char clear)
  52. {
  53.         switch (line)        //选择行
  54.         {
  55.                 case 1:
  56.                         OLED_Fill(0, 0, 127, 15, 0);        //清除原来的显示
  57.                         Show_Str(0, 0, sOption[FirstLineDisIndex].WordMete*8, 16,
  58.                                 sOption[FirstLineDisIndex].KeyWord, 16, clear);
  59.                         break;
  60.                 case 2:
  61.                         OLED_Fill(0, 16, 127, 31, 0);        //清除原来的显示
  62.                         Show_Str(0, 16, sOption[FirstLineDisIndex+1].WordMete*8, 16,
  63.                                 sOption[FirstLineDisIndex+1].KeyWord, 16, clear);
  64.                         break;
  65.                 case 3:
  66.                         OLED_Fill(0, 32, 127, 47, 0);        //清除原来的显示
  67.                         Show_Str(0, 32, sOption[FirstLineDisIndex+2].WordMete*8, 16,
  68.                                 sOption[FirstLineDisIndex+2].KeyWord, 16, clear);
  69.                         break;
  70.                 case 4:
  71.                         OLED_Fill(0, 48, 127, 63, 0);        //清除原来的显示
  72.                         Show_Str(0, 48, sOption[FirstLineDisIndex+3].WordMete*8, 16,
  73.                                 sOption[FirstLineDisIndex+3].KeyWord, 16, clear);
  74.                         break;
  75.                 default :
  76.                         break;
  77.         }
  78.         delay_ms(10);
  79. }

  80. /**
  81.   * @name        void Display_OLEDMenu (void)
  82.   * @brief  刷新菜单功能函数
  83.   * 采用的do{}while(0)循环
  84.   * @param        none
  85.   * @retval        none
  86.   */
  87. void Display_OLEDMenu (void)
  88. {
  89.     unsigned char LineMete =  Level[sOption[SelectIndex].KeyLevel][2]; //循环量,显示行数
  90.         /*
  91.                 unsigned char LineMtet=Level[sOption[当前选定行对应的索引号].菜单选项所属菜单表号][2]
  92.         */
  93.         OLED_Fill(0, 0, 128, 64, 0);        //清屏,否则会出现一些乱码 ,写0来清屏
  94.         delay_ms(10);
  95.     do                  //分别显示各行菜单项
  96.     {
  97.                 OLED_Fill(0, 0, 127, 15, 0);
  98. //在指定位置开始显示一个字符串            
  99. //支持自动换行
  100. //(x,y):起始坐标
  101. //width,height:区域
  102. //str  :字符串
  103. //size :字体大小
  104. //mode:0,非叠加方式;1,叠加方式
  105. //unsigned char FirstLineDisIndex = 0;屏幕第一行显示的索引号       
  106. //unsigned char *KeyWord;       //菜单选项文字描述指针
  107. //unsigned char WordMete;       //菜单选项描述文字字节数                       
  108.                 Show_Str(0, 0, sOption[FirstLineDisIndex].WordMete*8, 16,
  109.                                            sOption[FirstLineDisIndex].KeyWord, 16, 1);
  110.                         //unsigned char LineMete =  Level[sOption[SelectIndex].KeyLevel][2]; //循环量,显示行数
  111.         if(--LineMete == 0) break;
  112.                 OLED_Fill(0, 16, 127, 31, 0);
  113.                 Show_Str(0, 16, sOption[FirstLineDisIndex+1].WordMete*8, 16,
  114.                                             sOption[FirstLineDisIndex+1].KeyWord, 16, 1);
  115.         if(--LineMete == 0) break;
  116.                 OLED_Fill(0, 32, 127, 47, 0);
  117.                 Show_Str(0, 32, sOption[FirstLineDisIndex+2].WordMete*8, 16,
  118.                                             sOption[FirstLineDisIndex+2].KeyWord, 16, 1);
  119.         if(--LineMete == 0) break;
  120.                 OLED_Fill(0, 48, 127, 63, 0);
  121.                 Show_Str(0, 48, sOption[FirstLineDisIndex+3].WordMete*8, 16,
  122.                                             sOption[FirstLineDisIndex+3].KeyWord, 16, 1);
  123.     }
  124.     while(0);
  125.         Select_Line(SelectLine_L, 1);        //消除上一行反白
  126.         Select_Line(SelectLine, 0);        //填充所需反白
  127. }

  128. /**
  129.   * @name        bool MenuLevelStart (void)
  130.   * @brief  判断当前索引是否是表单第一项功能函数
  131.   * @param        none
  132.   * @retval        返回Bit标志,是第一项返回TURE,不是返回FALSE
  133.   */
  134. bool MenuLevelStart (void)
  135. {
  136.     unsigned char i = MENULEVEL;
  137.     do
  138.     {
  139.         i--;
  140.         if(SelectIndex == Level[i][0])
  141.             return TURE;
  142.     }
  143.     while(i);
  144.     return FALSE;
  145. }

  146. /**
  147.   * @name        bool MenuLevelEnd (void)
  148.   * @brief  判断当前索引是否是表单最后一项功能函数
  149.   * @param        none
  150.   * @retval        返回Bit标志,是最后一项返回TURE,不是返回FALSE
  151.   */
  152. bool MenuLevelEnd (void)
  153. {
  154.     unsigned char i = MENULEVEL;
  155.     do
  156.     {
  157.         i--;
  158.         if(SelectIndex == Level[i][1])
  159.             return TURE;
  160.     }
  161.     while(i);
  162.     return FALSE;
  163. }

  164. /**
  165.   * @name        void MenuUpOneOption (void)
  166.   * @brief  菜单上移一项函数
  167.   * @param        none
  168.   * @retval        none
  169.   */
  170. void MenuUpOneOption (void)
  171. {
  172.     if(MenuLevelStart ())         //如果当前为表单第一项
  173.     {
  174.         if(Level[sOption[SelectIndex].KeyLevel][2] >= 4) //并且表单中选项数目大于等于4个
  175.         {
  176.             FirstLineDisIndex = Level[sOption[SelectIndex].KeyLevel][1] - 3; //第一行显示索引号为倒数第四项
  177.             SelectIndex = Level[sOption[SelectIndex].KeyLevel][1];   //选择索引为表单最后一项
  178.             SelectLine_L = SelectLine;        //记录原来行
  179.                         SelectLine = 4;             //标记选择行为第四行
  180.         }
  181.         else            //如果选项数目并不大于四个
  182.         {
  183.             SelectIndex = Level[sOption[SelectIndex].KeyLevel][1];   //选择索引为当前表单最后一个
  184.             SelectLine_L = SelectLine;        //记录原来行
  185.                         SelectLine = Level[sOption[SelectIndex].KeyLevel][2];   //显示行表单数目(最后一个)
  186.         }
  187.     }
  188.     else        //如果当前不是开始索引
  189.     {
  190.         if(SelectLine == 1)  //并且已经在屏幕最上边一行
  191.         {
  192.             FirstLineDisIndex--;  //显示索引上移
  193.             SelectIndex--;    //选择索引自减
  194.                         SelectLine_L = SelectLine;        //记录原来行
  195.             SelectLine = 1;    //选择行还是第一行
  196.         }
  197.         else       //如果不是第一行
  198.         {
  199.                         SelectLine_L = SelectLine;        //记录原来行
  200.             SelectLine--;    //选择行自减
  201.             SelectIndex--;    //选择索引自减
  202.         }
  203.     }
  204.         Display_OLEDMenu();    //刷新屏幕显示
  205. }

  206. /**
  207.   * @name        void MenuDownOneOption (void)
  208.   * @brief  菜单下移一项函数
  209.   * @param        none
  210.   * @retval        none
  211.   */
  212. void MenuDownOneOption (void)
  213. {
  214.     if(MenuLevelEnd ())        //如果当前是表单最后一个索引
  215.     {
  216.         FirstLineDisIndex = Level[sOption[SelectIndex].KeyLevel][0]; //第一行显示索引为表单第一个选项
  217.         SelectIndex = Level[sOption[SelectIndex].KeyLevel][0];   //选择索引为表单第一个选项索引
  218.         SelectLine_L = SelectLine;        //记录原来行
  219.                 SelectLine = 1;             //选择行为第一行
  220.     }
  221.     else           //如果不是最后的索引
  222.     {
  223.         if(SelectLine != 4)     //如果当前不是屏幕最底行
  224.         {
  225.                         SelectIndex++;       //选择索引自加
  226.             SelectLine_L = SelectLine;        //记录原来行
  227.                         SelectLine++;       //选择行下移
  228.         }
  229.         else          //如果是屏幕最低行
  230.         {
  231.             FirstLineDisIndex++;     //第一行显示下移
  232.             SelectIndex++;       //选择索引自加
  233.         }
  234.     }
  235.         Display_OLEDMenu();    //刷新屏幕显示
  236. }

  237. /**
  238.   * @name        void MenuEnterOption (void)
  239.   * @brief  进入某项功能函数
  240.   * @param        none
  241.   * @retval        none
  242.   */
  243. void MenuEnterOption (void)
  244. {
  245.     LastIndex = SelectIndex;           //标记进入前的索引号(以便判断具体功能)
  246.     SelectIndex = sOption[SelectIndex].EnterIndex;      //更新选择索引为之前索引号对应进入索引
  247.     if(SelectIndex != OPTIONMETE - 1)        //如果当前索引不是功能选择索引
  248.     {
  249.         FirstLineDisIndex = Level[sOption[SelectIndex].KeyLevel][0]; //第一行显示为进入表单第一项
  250.         SelectLine_L = SelectLine;
  251.                 SelectLine = 1;             //设定第一行为选择行
  252.         Display_OLEDMenu ();                    //刷新菜单
  253.     }
  254.     else
  255.         {
  256.         FunctionAction ();           //如果是功能选择项,进入功能分支判断函数
  257.         }
  258. }

  259. /**
  260.   * @name        void MenuCancelOption (void)
  261.   * @brief  菜单退出功能函数
  262.   * @param        none
  263.   * @retval        none
  264.   */
  265. void MenuCancelOption (void)
  266. {
  267.     if(SelectIndex != OPTIONMETE - 1)        //如果不是从功能返回
  268.         {
  269.         SelectIndex = sOption[SelectIndex].CancelIndex;     //选择索引为选项返回索引
  270.         }
  271.     else                //如果是从功能返回
  272.         {
  273.         SelectIndex = LastIndex;          //索引等于进入前保存索引
  274.         }
  275.     if(Level[sOption[SelectIndex].KeyLevel][2] >= 4)    //如果返回表单选项数目大于4个
  276.     {
  277.         if(SelectIndex > Level[sOption[SelectIndex].KeyLevel][1] - 3) //根据返回选项确定显示首项
  278.         {
  279.             FirstLineDisIndex = Level[sOption[SelectIndex].KeyLevel][1] - 3;
  280.             SelectLine_L = SelectLine;
  281.                         SelectLine =  4 - (Level[sOption[SelectIndex].KeyLevel][1] - SelectIndex);
  282.         }
  283.         else               //一般显示方式
  284.         {
  285.             FirstLineDisIndex = SelectIndex;       //第一行显示索引
  286.                         SelectLine_L = SelectLine;
  287.             SelectLine = 1;            //选择第一行
  288.         }
  289.     }
  290.     else                //如果返回表单选项数目不足4个
  291.     {
  292.         FirstLineDisIndex = Level[sOption[SelectIndex].KeyLevel][0];   //第一行显示索引为表单第一项
  293.         SelectLine_L = SelectLine;
  294.                 SelectLine = SelectIndex -  Level[sOption[SelectIndex].KeyLevel][0] + 1; //选择行标志为当前选择索引对应行
  295.     }
  296.         Display_OLEDMenu ();               //刷新菜单
  297. }

  298. /**
  299.   * @name        void ShutDown (void)
  300.   * @brief  某一项功能函数     实际应该改为实际功能函数
  301.   * @param        none
  302.   * @retval        none
  303.   */
  304. void SystemState (void)
  305. {
  306.         OLED_Clear();        //清屏
  307.         delay_ms(1);
  308.         Show_Str(16, 29, 128, 16, "系统版本V1.0", 16, 1);
  309. }

  310. void System_Help (void)
  311. {
  312.         OLED_Clear();        //清屏
  313.         delay_ms(1);
  314.         Show_Str(0, 0,  128, 16, "1.上下键选择", 16, 1);
  315.         Show_Str(0, 16, 128, 16, "2.左键确定", 16, 1);
  316.         Show_Str(0, 32, 128, 16, "3.右键退出", 16, 1);
  317. }

  318. void SystemTest (void)
  319. {
  320.         OLED_Clear();        //清屏
  321.         delay_ms(1);
  322.         if (font_init())
  323.         {
  324.                 OLED_Fill(0, 16, 128, 31, 0);
  325.                 Show_Str(32, 16, 128, 16, "字库错误", 16, 1);       
  326.         }
  327.         else
  328.         {
  329.                 OLED_Fill(0, 16, 128, 31, 0);
  330.                 Show_Str(32, 16, 128, 16, "字库正常", 16, 1);
  331.         }
  332. }

  333. u16 radio = 0x7F;
  334. void OLED_Light (void)
  335. {
  336.         u8 flag = 1;
  337.         OLED_Clear();        //清屏
  338.         delay_ms(1);
  339.         Show_Str(32, 0, 128, 16, "亮度调节", 16, 1);
  340.         OLED_DrawRectangle(0, 16, 93, 31, 1);        //画进度条的边框
  341.         while (1)
  342.         {
  343.                 /*限制进度条的范围*/
  344.                 if (radio <= 2)
  345.                 {
  346.                         radio = 2;
  347.                 }
  348.                 else if (radio >= 255)
  349.                 {
  350.                         radio = 255;
  351.                 }
  352.                 OLED_Write_Com(0x81); //对比度设置
  353.                 OLED_Write_Com(radio); //1~255;默认0X7F (亮度设置,越大越亮)
  354.                 if (flag == 1)
  355.                 {
  356.                         flag = 0;
  357.                         OLED_Fill(1+(92 * radio / 255), 17, 93, 31, 0);        //消除进度条的多余部分
  358.                         OLED_Fill(1, 17, 1+(92 * radio / 255), 31, 1);        //填充进度条
  359.                         OLED_ShowNum(94, 16, (100 * radio / 255), 3, 16, 1);        //显示进度百分比
  360.                         OLED_ShowChar(120, 16, '%', 16, 1);
  361.                 }
  362.                 delay_ms(10);
  363.                 switch (KEY_Scan(1))        //按键扫描
  364.                 {
  365.                         case KEY_UP :        //按上键增加亮度
  366.                                 flag = 1;
  367.                                 radio += 2;
  368.                                 break;
  369.                         case KEY_DOWN :        //按下键减小亮度
  370.                                 flag = 1;
  371.                                 radio -= 2;
  372.                                 break;
  373.                         case KEY_RIGHT :        //按右键退出
  374.                                 MenuCancelOption();
  375.                                 return;
  376.                         default :
  377.                                 break;
  378.                 }
  379.         }
  380. }

  381. void NoThisFunction (void)
  382. {
  383.     unsigned char Font[] = {"没有这个功能"};
  384.         OLED_Clear();        //清屏
  385.         delay_ms(1);
  386.         Show_Str(16, 16, 128, 16, Font, 16, 1);
  387.         delay_ms(500);
  388.     MenuCancelOption();
  389. }

  390. /**
  391.   * @name        void FunctionAction (void)
  392.   * @brief  具体功能散转函数
  393.   * @param        none
  394.   * @retval        none
  395.   */
  396. void FunctionAction (void)
  397. {
  398.     switch (LastIndex)            //根据进入前的索引判断具体函数
  399.     {
  400.                 case 0:
  401.                         OLED_Light();
  402.                         break;
  403. //                case 1:
  404. //                        break;
  405. //                case 2:
  406. //                        break;
  407.                 case 2:
  408.                         SystemTest();
  409.                         break;
  410. //                case 4:
  411. //                        break;
  412.                 case 4:
  413.                         System_Help();
  414.                         break;
  415.                 case 5:
  416.                         SystemState();
  417.                         break;
  418.                 default:
  419.                         NoThisFunction();
  420.                         break;      //如果没有具体操作,显示没有这个功能
  421.     }
  422. }

  423. /**
  424.   * @name        void KeyCodeAction (unsigned char KeyCode)
  425.   * @brief  菜单操作按键处理散转函数
  426.   * @param        KeyCode:按键值   实际使用应根据自己的按键重新编写case项
  427.   * @retval        none
  428.   */
  429. void KeyCodeAction (unsigned char KeyCode)
  430. {
  431.     switch (KeyCode)
  432.     {
  433.                 case KEY_UP:
  434.                         MenuUpOneOption();
  435.                         break;   //如果是向上按键,则菜单向上,以下类似
  436.                 case KEY_DOWN:
  437.                         MenuDownOneOption();
  438.                         break;
  439.                 case KEY_LEFT:
  440.                         MenuEnterOption();
  441.                         break;
  442.                 case KEY_RIGHT:
  443.                         MenuCancelOption();
  444.                         break;
  445.                 default:
  446.                         break;
  447.     }
  448. }
复制代码

一周热门 更多>