您的位置:首页 > 编程语言 > C语言/C++

多级菜单框架(C实现)

2017-05-22 20:25 323 查看
以前见过的多级菜单都是用索引号实现,但是这种菜单修改不易,正好这段时间我要在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",&spee
4000
d);

SetPage(4,1,"YuZhi");
SetOptContent(4,"yuzhi",&yuzhi);
EndPageSet();


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

效果图:







内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息