多级菜单框架(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();


我感觉这样设置就方便多了。。。
效果图:


--------------------- 
作者:香蕉割草机 
来源:CSDN 
原文:https://blog.csdn.net/m0_37565736/article/details/72629748?utm_source=copy 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值