多级菜单框架(C实现)

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

C文件

#include "parallelmenu.h"
#include "include.h"
#include <string.h>
#define check 1
Page* 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 24

typedef 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();


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

效果图:






猜你喜欢

转载自blog.csdn.net/m0_37565736/article/details/72629748