基于链表的多级菜单设计

基于链表的多级菜单设计

前言

最近在做一个简单的界面,需要用到多级菜单,一开始使用的是传统的索引法,在修改时比较乱,在网上有用链表写的,虽然一致都在用c语言,却很少使用链表,于是今天早上便打算用链表制作一个多级菜单,经过一天的努力,终于完成了一个简单的框架,现在只可以添加菜单,而且没有级数限制。 目前只是在gcc下运行成功,还没有在单片机上运行。

主体

传统的双向链表可以寻找上下级的关系,而在多级菜单中还包括同级关系,因此链表的解构应该是树形,包括,父级,子级,同级上和同级下
这里定义一个结构体

typedef struct _menu
{
    struct _menu * last;//父极菜单指针
    struct _menu * same_last;//同级菜单下一项指针
    struct _menu * same_next;//同级菜单上一项指针
    char * menu_name;//当前功能名称
    int id;//当前功能号
    void (*funsion)();//功能
    struct _menu*next;//子级菜单
  
}menu_t;

这里,我们还需要几个变量
1.我们需要知道链表当前位置
2.通过按键上下可以在同级之间切换,左右分别表示退出和返回,但是如果我们进入一个界面不想通过上下左右切换链表,所以我们还需要一个全局变量,当这个变量为1时是正常操作,当变量为非1时,我们将获取的按键值交给一个全局变量,故我们需要两个变量

struct {
menu_t *now;//当前链表位置
int ctrl;
char input;
}sys_info;

接下来便是创建表头

menu_t*add_funsion(menu_t *head,void * fun,char * str){    //添加一个功能 head为该界面的第一项,自动在该界面后添加一项功能
	menu_t *p = NULL,*pr = head;  
	p = (menu_t *)malloc(sizeof(menu_t)) ; 
	if(p == NULL){		
		printf("NO enough momery to allocate!\n");
		exit(0);
	}
	if(head == NULL){		
		head = p;	//head为空,创建头节点	
        printf("创建头节点\n");						
	}else{				//如果不是创建头节点	
        int i=1;					                       
		while(pr->same_next!= NULL){		//找到同级菜单最后的表
        {
            i++;
            pr = pr->same_next;
        }
			
		}
		pr->same_next = p;	//在同级菜单尾部创建一个功能
        p->same_last=pr;
        p->last=head->last;
        p->id=i;
	}
     p->funsion=fun;
	 p->menu_name=str;
	p->same_next = NULL;//下一个同级功能为空
    p->next=NULL;			//下一个子集功能为空
	return head;		
}

上面的函数中如果head是一个空指针,则创建头节点,如果不是空指针,则在其同级最后添加一个结构
然后是在一个目录功能下新建一个目录

menu_t * set_page(menu_t * head,int num)//输入为页的表头
{
    for(int i=0;i<num;i++)
    {
        if(head->same_next!=NULL)
        head=head->same_next;
        else
        {
            printf("超出当前功能号\n");
        }
        
    }
     if(head->next!=NULL)
    head=head->next;
    else
    {

        printf("创建子菜单\n");
    menu_t *p = NULL;   
	p = (menu_t *)malloc(sizeof(menu_t)) ; 
	if(p == NULL){		
		printf("NO enough momery to allocate!\n");
		exit(0);
	}
								                       
		head->next=p;
        p->last=head;
        p->id=0;//当前功能号为0
        p->same_last=NULL;
        p->same_next=NULL;
        return p;
    }
    
    return head;
}

第一个head指针为当前目录真正,第二个num代表要在当前目录那一项创建子级,并将创建子级的指针返回,但是,需要注意的是返回的指针已经开辟了内存,并没有使用,因此需要对此指针内容进行赋值

void set_fun(menu_t *menu,void * fun,char * str)//设置函数和功能
{
        menu->funsion=fun;
        menu->menu_name=str;
}

至此主要函数就已经写完了
然后就是进入目录时的刷新

void fun1()
{
   printf("%s","\033[1H\033[2J");//linux下的清屏函数,window下请用system("cls");
    printf("使用键盘选择以下功能\n");
    if(sys_info.now->last!=NULL)//如果父极不为空
    {
        menu_t * start=sys_info.now->last->next;//start指向同级第一个
        while(start!=NULL)//将所有功能打在屏幕上,如果功能和选中功能一样,变色
        {
            
            if(start->menu_name==sys_info.now->menu_name)//
            {
                printf("********%s*********\n",start->menu_name);
            }
            else
            {
                printf("    ****%s****\n",start->menu_name);
            }
            start=start->same_next;

        }
    }
    else
    {
        printf("父极为空");
    }


}

由于是在linux下写完,清屏函数在window下需要system
下面是完整代码

#include <stdio.h>
#include <stdlib.h>
typedef struct _menu
{
    struct _menu * last;//父极菜单指针
    struct _menu * same_last;//同级菜单下一项指针
    struct _menu * same_next;//同级菜单上一项指针
    char * menu_name;//当前功能名称
    int id;//当前功能号
    void (*funsion)();//功能
    struct _menu*next;//子级菜单
  
}menu_t;

struct {
menu_t *now;//当前链表位置
int ctrl;
char input;
}sys_info;

menu_t * set_page(menu_t * head,int num)//输入为页的表头
{
    for(int i=0;i<num;i++)
    {
        if(head->same_next!=NULL)
        head=head->same_next;
        else
        {
            printf("超出当前功能号\n");
        }
        
    }
     if(head->next!=NULL)
    head=head->next;
    else
    {

        printf("创建子菜单\n");
    menu_t *p = NULL;   
	p = (menu_t *)malloc(sizeof(menu_t)) ; 
	if(p == NULL){		
		printf("NO enough momery to allocate!\n");
		exit(0);
	}
								                       
		head->next=p;
        p->last=head;
        p->id=0;//当前功能号为0
        p->same_last=NULL;
        p->same_next=NULL;
        return p;
    }
    
    return head;
}

menu_t*add_funsion(menu_t *head,void * fun,char * str){    //添加一个功能 head为该界面的第一项,自动在该界面后添加一项功能
	menu_t *p = NULL,*pr = head;   
    
	p = (menu_t *)malloc(sizeof(menu_t)) ; 
	if(p == NULL){		
		printf("NO enough momery to allocate!\n");
		exit(0);
	}
	if(head == NULL){		
		head = p;	//head为空,创建头节点	
        printf("创建头节点\n");						
	}else{				//如果不是创建头节点	
        int i=1;					                       
		while(pr->same_next!= NULL){		//找到同级菜单最后的表
        {
            i++;
            pr = pr->same_next;
        }
			
		}
		pr->same_next = p;	//在同级菜单尾部创建一个功能
        p->same_last=pr;
        p->last=head->last;
       
       
        p->id=i;
	}
     p->funsion=fun;
	 p->menu_name=str;
	p->same_next = NULL;//下一个同级功能为空
    p->next=NULL;			//下一个子集功能为空
	return head;		
}
 menu_t * add_child(menu_t *head)//添加子级
{
    	menu_t *p = NULL;   
	p = (menu_t *)malloc(sizeof(menu_t)) ; 
	if(p == NULL){		
		printf("NO enough momery to allocate!\n");
		exit(0);
	}
	if(head == NULL){		
		printf("输入head错误,添加子级失败\n");							
	}else{										                       
		head->next=p;
        p->last=head;
        p->same_last=NULL;
        p->same_next=NULL;
	}
    return p;
}
void fun1()
{
   printf("%s","\033[1H\033[2J");//linux下的清屏函数,window下请用system("cls");
    printf("使用键盘选择以下功能\n");
    if(sys_info.now->last!=NULL)//如果父极不为空
    {
        menu_t * start=sys_info.now->last->next;//start指向同级第一个
        while(start!=NULL)//将所有功能打在屏幕上,如果功能和选中功能一样,变色
        {
            
            if(start->menu_name==sys_info.now->menu_name)//
            {
                printf("********%s*********\n",start->menu_name);
            }
            else
            {
                printf("    ****%s****\n",start->menu_name);
            }
            start=start->same_next;

        }
    }
    else
    {
        printf("父极为空");
    }


}
void kong()//空函数
{
    printf("%s","\033[1H\033[2J");//linux下的清屏函数,window下请用system("cls");
    printf("***多级菜单显示****");
}
void set_fun(menu_t *menu,void * fun,char * str)//设置函数和功能
{
        menu->funsion=fun;
        menu->menu_name=str;
}
void switch_input()//判断输入
{
  

    scanf("%c", & sys_info.input);//把a仍给系统,交给对应函数处理
    if (sys_info.ctrl)//按键控制链表
    {
        switch (sys_info.input)
    {
     case 'w'://if(sys_info.now->same_last!=NULL)
     sys_info.now=sys_info.now->same_last;
     
        break;
         case 's'://if(sys_info.now->same_next!=NULL)
         sys_info.now=sys_info.now->same_next;
      
        break;
         case 'a':// 左相当于返回
         if(sys_info.now->last!=NULL)
         sys_info.now=sys_info.now->last;
     
        break;
         case 'd'://右相当于确认
     if(sys_info.now->next!=NULL)
         sys_info.now=sys_info.now->next;
        break;
    
    default:
        break;
    }
        sys_info.now->funsion();
    }
}
void main()
{
    sys_info.ctrl=1;

    menu_t *head=NULL;
    head=add_funsion(head,kong,"添加头节点");//添加头节点

     menu_t *first=set_page(head,0);//主页面
    set_fun(first,fun1,"第一页选项一");
   add_funsion(first,fun1,"第一页选项二");
    add_funsion(first,fun1,"第一页选项三");


    menu_t *second=set_page(first,0);//第一个功能的页面 二级菜单
    set_fun(second,fun1,"选项一的选项一");
    add_funsion(second,fun1,"选项一的选项二");
    add_funsion(second,fun1,"选项一的选项三");
    sys_info.now=first;

    menu_t *three=set_page(first,1);//第一个功能的页面 二级菜单
    set_fun(three,fun1,"选项二的选项一");
    add_funsion(three,fun1,"选项二的选项二");
    add_funsion(three,fun1,"选项二的选项三");

    menu_t *four=set_page(second,0);//第一个功能的页面的第一个页面  三级菜单
    set_fun(four,fun1,"选项一的选项一的选项一");
    add_funsion(four,fun1,"选项一的选项一选项二");
    add_funsion(four,fun1,"选项一的选项一选项三");
    fun1();
    sys_info.now=first;
    while(1)
    {
        switch_input();
    }

}

发布了4 篇原创文章 · 获赞 1 · 访问量 183

猜你喜欢

转载自blog.csdn.net/qq_33862616/article/details/105618186