多级菜单框架(C实现)

来源:互联网 发布:天刀捏脸数据金木研 编辑:程序博客网 时间:2024/06/17 15:26

以前见过的多级菜单都是用索引号实现,但是这种菜单修改不易,正好这段时间我要在OLED上显示菜单,所以就编了一个框架出来,代码如下

C文件

#include "parallelmenu.h"#include "include.h"#include <string.h>#define check 1Page* current_page;Option* current_opt;Page* start_of_pagelist;char pagenum;void SetPageNum(int num){    #if check    if(num>MAX_NUM_OF_PAGE) return;    #endif // check    pagenum=num;    start_of_pagelist=(Page*)malloc(num*sizeof(Page));}void SetPage(int num,int optnum,unsigned char* str){    #if check    if(num>pagenum||num<1) return;    #endif // check    optnum++;//加页面名字    current_page=start_of_pagelist+num-1;    current_page->optnum=optnum;    current_page->option=(Option*)malloc(optnum*sizeof(Option));    current_opt=current_page->option;    current_opt->flag=(Type)0;    current_opt->content.str=str;    current_opt->name=0;}SmallNum GetSmallNum(float num){    SmallNum smallnum;    smallnum.integer=(int)num;    smallnum.leave=(int)((num-(int)num)*100);    return smallnum;}void SetOptContent(char flag,unsigned char* name,void* content){    #if check    if(current_opt>=current_page->option+current_page->optnum-1) return;    #endif // check    current_opt++;    current_opt->flag=(Type)flag;    switch(flag)    {        case 0:        case 3: current_opt->content.str=(unsigned char*)content;break;        case 1:        case 4: current_opt->content.num=(int*)content;break;        case 2:        case 5: current_opt->content.smallnum=GetSmallNum(*(float*)content);        default: break;    }    current_opt->name=name;}void EndPageSet(){    current_page=start_of_pagelist;    current_page->selection=0;    current_opt=current_page->option;    _SetPosition();}void _SetPosition(){    OLED_Clear();    char leave=current_page->optnum-current_page->selection;    if(leave>4) leave=4;    char i=0;    for(;i<leave;i++) DrawOpt((OptPosition)i);    OLED_Refresh_Gram();}void process_KeyAction(KeyValue keyvalue){    switch(keyvalue)    {        case keyup: process_optchange(1);break;        case keydown: process_optchange(0);break;        case keyleft: process_valuechange(1);break;        case keyright: process_valuechange(0);break;        case keyenter: process_Enter();break;        default: break;    }}void process_optchange(char flag){  if(flag)//上键  {    if(current_page->selection==0);    else current_page->selection--;  }  else//下键  {    if(current_page->selection==current_page->optnum-1);    else current_page->selection++;  }  current_opt=current_page->option+current_page->selection;//更新  _SetPosition();//绘制}//只把current_opt变为选择选项void process_valuechange(char flag){if(current_page->selection==0){    if(flag)//回退    {        if(current_page-start_of_pagelist)        {            current_page--;            current_opt=current_page->option;            current_page->selection=0;        }        else        {            current_page=start_of_pagelist+pagenum-1;            current_opt=current_page->option;            current_page->selection=0;        }    }    else//确认    {        if(current_page-start_of_pagelist<pagenum-1)        {            current_page++;            current_opt=current_page->option;            current_page->selection=0;        }        else        {            current_page=start_of_pagelist;            current_opt=current_page->option;            current_page->selection=0;        }    }_SetPosition();//绘制}else{switch(current_opt->flag)    {    //case adjustblestr: _adjustblestr(flag);break; //待扩展    case adjustablenum:      _adjustablenum(flag);break;     case adjustblesmall:      _adjustblesmall(flag);break;default: break;    }_SetPosition();//绘制}void process_Enter(){}void _adjustblestr(char flag){}void _adjustablenum(char flag){    if(flag)//左    {      if(*current_opt->content.num) (*current_opt->content.num)--;    }    else//右    {      if((*current_opt->content.num)<255) (*current_opt->content.num)++;    }}void _adjustblesmall(char flag){  static SmallNum _smallnum;  _smallnum=current_opt->content.smallnum;    if(flag)    {      if(_smallnum.integer||_smallnum.leave)      {          if(!_smallnum.leave)          {              _smallnum.integer--;              _smallnum.leave=99;          }          else _smallnum.leave--;      }    }    else    {        if((~_smallnum.integer)||(~_smallnum.leave))      {          if(_smallnum.leave==99)          {              _smallnum.integer++;              _smallnum.leave=0;          }          else _smallnum.leave++;      }    }    current_opt->content.smallnum=_smallnum;}



头文件

#ifndef _PARALLEL_MENU_H#define _PARALLEL_MENU_H#include  "common.h"#define MAX_NUM_OF_PAGE 24typedef enum//键值枚举变量{  keyup,  keydown,  keyleft,  keyright,  keyenter}KeyValue;typedef enum //屏幕位置枚举变量{  fristline,  secondline,  thirdline,  fourthline}OptPosition;typedef enum{    strings,//0    number,//1    smallnum,//2    adjustblestr,//3    adjustablenum,//4    adjustblesmall//5}Type;struct _SmallNum{    int integer;    unsigned char leave;};union optcontent{    unsigned char* str;    int* num;    struct _SmallNum smallnum;};struct _Page{    char optnum;//选项数目    struct _Option* option;//本页选项结构体数组指针    char selection;//当前选中的选项标号,从0开始计数};struct _Option{  Type flag;//用作标识普通选项与可调整选项的标志位  0普通 1可调整  unsigned char* name;  union optcontent content;};  typedef struct _Page Page;  typedef struct _Option Option;  typedef struct _SmallNum SmallNum;void SetPageNum(int num);void SetPage(int num,int optnum,unsigned char* str);void SetOptContent(char flag,unsigned char* name,void* content);void EndPageSet();void _SetPosition();void process_KeyAction(KeyValue keyvalue);void process_optchange(char flag);void process_valuechange(char flag);void process_Enter();void _adjustblestr(char flag);void _adjustablenum(char flag);void _adjustblesmall(char flag);





因为为了展现框架,即与平台无关,一些显示函数如DrawOpt没有给出,另外优化部分也去除掉了

这个框架支持float,int型变量调整,我感觉写的时候应该用到了一丢丢C++,也不枉费我之前的学习了,233

不过确实,用C来写面向对象会感觉不自在。。。

应用例子:

SetPageNum(4);    SetPage(1,3,"S3010-PID");    SetOptContent(5,"S-P",&SP);    SetOptContent(5,"S-I",&SI);    SetOptContent(5,"S-D",&SD);    SetPage(2,3,"Motor-PID");    SetOptContent(5,"M-P",&MP);    SetOptContent(5,"M-I",&MI);    SetOptContent(5,"M-D",&MD);    SetPage(3,1,"Trg-Speed");    SetOptContent(4,"Trg-V",&speed);    SetPage(4,1,"YuZhi");    SetOptContent(4,"yuzhi",&yuzhi);    EndPageSet();


我感觉这样设置就方便多了。。。

效果图:






原创粉丝点击