搜索
bottom↓
回复: 33

请教傻孩子大侠多级菜单的问题.

[复制链接]

出0入0汤圆

发表于 2008-8-21 20:47:22 | 显示全部楼层 |阅读模式
/**********************
*    目录结构体定义   *
**********************/
typedef struct datas
{
unsigned char MenuCount;                    //当前层节点数
unsigned int  str[8];                //菜单标题
void (*Subs)(void);                              //节点函数
struct datas const *ChildrenMenus;   //子节点
struct datas const *ParentMenus;     //父节点
}MenuItem;

MenuItem const MainMenu[]=
{
   {4,  {'时','间','设','置'},Main_son,   TimsMenu,   Null},
   {4,  {'参','数','设','置'},Main_son,   DatfMenu,   Null},
   {4,  {'系','数','标','定'},Main_son,   DatdMenu,   Null},
   {4,  {'退','出','设','置'},Exit_son,   Null,   Null},
};


void NullSubs(void)
{
}


int main()
{                       
    short KeyNum = 0xff;
     
    SystemInitialation();            //系统初始化
     
    ShowMenu();
        while(1)
        {
            ClearWatchDog();             //喂狗
            KeyNum = GetKeyNum();        //获取按键值

            /*******************目录操作*********************/
            
            /***************************************
            *   [按键说明]                         *
            *  ----------------------------------- *
            *   [K1]            UP(向上)           *
            *   [K5]            Down(向下)         *
            *   [K2]            Esc(后退)          *
            *   [K6]            Enter(确定)        *
            *   [K3]            返回根目录         *
            ***************************************/
            if (KeyNum != 0xff)
            {
             ShowMenu();
                 switch(KeyNum)
                 {
                     case UP:
                         UserChoose --;
                         if (UserChoose < 0)
                         {
                             UserChoose = MaxItems-1;
                         }
                         break;
                     case Esc:
                         if (MenuPoint[0].ParentMenus != &Null)
                         {
                             MenuPoint = MenuPoint[0].ParentMenus;
                             UserChoose = 0;
                             DisplayStart = 0;
                         }
                         break;
                     case Down:
                         UserChoose ++;
                         if (UserChoose == MaxItems)
                         {
                             UserChoose = 0;
                         }
                          
                         break;
                     case Enter:
                         if (MenuPoint[UserChoose].Subs != NullSubs)
                         {
                             (*MenuPoint[UserChoose].Subs)();
                         }
                         else if (MenuPoint[UserChoose].ChildrenMenus != &Null)
                         {
                             MenuPoint = MenuPoint[UserChoose].ChildrenMenus;
                             UserChoose = 0;
                             DisplayStart = 0;
                         }
                         break;
                     case Reset:
                         MenuPoint = MainMenu;
                         UserChoose = 0;
                         DisplayStart = 0;
                         break;
                 }
                  
                 if ((UserChoose < DisplayStart) || (UserChoose > (DisplayStart+3)))
                 {
                    DisplayStart = UserChoose;
                 }
                  
                 CLS
                 ShowMenu();
                  
            }
            /*******************目录操作*********************/
        }
         

}

请教傻孩子大侠,当进入void (*Subs)();函数后,如在里面设置完数据后,如何退出.还有菜单操作部分全部是死循环:即死等按键直到退出菜单。
 也就是说,进入菜单操作过程时,主程序中的其它程序就无法执行了.如何才能避免.大侠能不能发表一个最简单的示例.谢谢!

出0入0汤圆

发表于 2008-8-22 07:42:59 | 显示全部楼层
比较实际的一个问题!
我的做法是:定义一个全局变量(字符或整型,根据实际晶振选),每次键盘按下,给一个初值给变量(如100),每次中断中减1,直到为零,最后在按键识别函数增加对这个变量是否为零的检测,如变量=0则返回或弹回你想要的菜单!我的中断是20ms,20x200=4秒,即4秒返回!
个人愚见,不知道大家怎么做的?

出0入0汤圆

 楼主| 发表于 2008-8-22 19:05:54 | 显示全部楼层
在我的按键菜单里是每次按下时,将一个全局变量清0,在给定的时间内没有按键在次按下时,退出按键程序。但是一直没有做出一个好的多级菜单出来。看了傻孩子大侠的示例后,觉得算法很好,但是里面设置完数据后,如何退出。还有菜单操作部分全部是死循环:即死等按键直到退出菜单。这个部分一直没有想出好的算法,不知道有没有哪位大侠能指导一下。谢谢!在网上看到下面的示例觉得也没有想的很全。也存在这个问题。

void GetKeyInput(void)
{
void (*KeyFuncPtr)();    //按键功能指针

}
unsigned char KeyValue;
typedef   struct     
{   
  unsigned char state;  //当前索引号
  unsigned char keydn;  //同一级菜单下移索引号
  unsigned char keyon;  //同一级菜单上移索引号
  unsigned char keynext;  //下一级菜单索引号
  unsigned char keyback;  //上一级菜单索引号
  void  (*pFun)();  
}_Fun_Test;

_Fun_Test code KeyTab [23]=
{
  {0,1,5,6,0,lcdm},
  {1,2,0,10,1,lcdm2},
  {2,3,1,11,2,lcdm3},
  {3,4,2,12,3,lcdm4},
  {4,5,3,13,4,lcdm5},
  {5,0,4,14,5,lcdm6},
  {6,7,20,21,0,lcdse1},
  {7,15,6,22,0,lcdse2},
  {8,8,8,8,6,lcdth1},
  {9,9,9,9,6,lcdth2},
  {10,10,10,10,1,lcdsetemp},
  {11,11,11,11,2,lcdsetemp},
  {12,12,12,12,3,lcdsetemp},
  {13,13,13,13,4,lcdsetemp},
  {14,14,14,14,5,lcdsetemp},
  {15,16,7,8,0,lcdse3},
  {16,17,15,9,0,lcdse4},
  {17,18,16,17,0,lcdse5},
  {18,19,17,18,0,lcdse6},
  {19,20,18,19,0,lcdse7},
  {20,6,19,20,0,lcdse8},
  {21,21,21,21,6,simulation},
  {22,22,22,22,7,onoff}
};

//LEDRUN = 0;

KeyValue = P2 & 0XFF;   //
DelayMs(20*3);

lightflashon();    //工作标志灯
  
switch(KeyValue)
{
  case LCDKEY1:    //回车键,找出新的菜单状态编号
  {
   KeyFuncIndex=KeyTab[KeyFuncIndex].keynext;
   sound = 1;
   DelayMs(5*3);
   sound = 0;
   delchar();   //del all char
   delzipic();   //del haizi and picture
   break;
  }
  case LCDKEY2:    //向上键,找出新的菜单状态编号
  {
   KeyFuncIndex=KeyTab[KeyFuncIndex].keyon;
   sound = 1;
   DelayMs(5*3);
   sound = 0;
   break;
  }
  case LCDKEY3:    //向下键,找出新的菜单状态编号
  {
   KeyFuncIndex=KeyTab[KeyFuncIndex].keydn;
   sound = 1;
   DelayMs(5*3);
   sound = 0;
   break;
  }
  case LCDKEY4:   //返回键,找出新的菜单状态编号
  {
   KeyFuncIndex=KeyTab[KeyFuncIndex].keyback;
   sound = 1;
   DelayMs(5*3);
   sound = 0;
   delchar();   //del all char
   delzipic();   //del haizi and picture
   break;
  }
  default:     //按键错误的处理
   break;
}
KeyFuncPtr=KeyTab[KeyFuncIndex].pFun;
(*KeyFuncPtr)();   //执行当前按键的操作

lightflashoff();   //工作标志灯

//LEDRUN = 1;
}

出0入296汤圆

发表于 2008-8-25 10:51:25 | 显示全部楼层
简单的做法,就是全部使用状态机,就能解决你的疑惑。
可以尝试自己先画状态图,再用if或者switch结构来实现这个状态机。

出0入0汤圆

 楼主| 发表于 2008-8-25 19:16:55 | 显示全部楼层
我原来就是用的 switch,但是看了你的多级菜单的示例后,发现进与出父子菜单真的很方便。但是现在想不出一个好的方法来,如何才能在你示例的基础,让数据设置变的很简单。还有如何能避免菜单操作部分是死循环。

出0入296汤圆

发表于 2008-8-25 19:58:13 | 显示全部楼层
给你一个诀窍,你把所有的死循环都用状态机来实现。

出0入0汤圆

发表于 2008-8-25 21:50:35 | 显示全部楼层
typedef struct _menu_item
{
        FLASH INT8U* strItemText;
        HANDLE pfItemFunc;
}MENU_ITEM;


typedef struct _menu
{
        void* pMenuItemBase;
        INT8U  FLASH * pTitle;
        INT8U TotalItem;
        INT8U CurItem;
}MENU;

typedef struct _bar_menu
{
        void* pMenuItemBase;
        INT8U  FLASH * pTitle;
        INT8U TotalItem;
        INT8U CurItem;

        INT8U WhereItem;
        INT8U Range;
}BAR_MENU;

typedef struct _icon_menu
{
        void* pMenuItemBase;
        INT8U  FLASH * pTitle;
        INT8U  TotalItem;
        INT8U  CurItem;

        INT8U FLASH** pIconDataBase;
}ICON_MENU;


typedef MENU* (*MENU_STK)[];

typedef struct _menu_stk_obj
{
        MENU_STK pMenuStack;
        INT8U Top;
        INT8U Size;
}MENU_STK_OBJ;

用堆栈也行的。上面是我的几种菜单的定义。
至于LZ的问题,设一个刷新屏幕的标志,主程序定时检查标志就行,有就刷一次,没有就算了。

出0入18汤圆

发表于 2009-4-22 16:33:24 | 显示全部楼层
收藏学习中!

出0入0汤圆

发表于 2010-3-27 11:59:47 | 显示全部楼层
回复【3楼】Gorgon Meducer 傻孩子
-----------------------------------------------------------------------

多谢提醒

出0入0汤圆

发表于 2010-5-13 21:07:15 | 显示全部楼层
太好了,我看了傻孩子大侠书中的讲的知识点以后还是有点疑惑,碰巧这里有这个主题,再学习学习一下!

出0入0汤圆

发表于 2010-8-25 14:28:37 | 显示全部楼层
多谢各位大侠,受教了。

出0入0汤圆

发表于 2010-10-26 11:40:24 | 显示全部楼层
Gorgon Meducer 傻孩子大侠 :
    我一直在琢磨你写的菜单结构,看你用的是结构体,里面把数据和处理数据的函数放在一个结构体里面,我百看也不能理解是怎么实现的? 这个好像是面向对象的程序设计了吧!? 可是我没有学过C++, 对面向对象的程序设计方法不理解? 你能不能详细的指导指导我们一下啊!?不胜感激!!!!!!!!!!!

出0入296汤圆

发表于 2010-10-28 10:17:09 | 显示全部楼层
to 【11楼】 liaogang1314
用C语言实现面向对象的技术,请参考下面链接里面的文档(数据结构章节)
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3239709&bbs_page_no=1&bbs_id=3039

出0入0汤圆

发表于 2010-10-29 11:37:08 | 显示全部楼层
多谢傻孩子大侠!!谢谢你无私的指导!

出0入0汤圆

发表于 2010-10-29 22:40:00 | 显示全部楼层
还有 请教Gorgon Meducer 傻孩子大侠:
你发布的这个结构体菜单是不是用了链表或者队列等数据结构里面的一些知识呢 我仅仅学了数据结构里面的一点点单向链表知识 其他的没学过 老是看不懂你的 郁闷呀!还请大侠百忙之中告知一二!不胜感激!!!!!!!!!!!!!!多多谢!!!!!!!!!

出0入296汤圆

发表于 2010-11-1 00:23:41 | 显示全部楼层
队列应该没有用,严格的说,用的是数据结构里面“树”的知识。(更严格的说,其实是“图”)

出0入0汤圆

发表于 2010-11-1 07:54:27 | 显示全部楼层
Gorgon Meducer 傻孩子:
                太谢谢大侠的指导了!真的很不好意思!让你手把手的教我!!我去好好看看数据结构 争取把你的菜单结构搞懂!!!!做出一个自己的小东西来!!!!!再次表示忠心的感谢!!!!!

出0入0汤圆

发表于 2010-11-3 22:52:47 | 显示全部楼层
请教一下,这个菜单程序,如果用在51单片机内可以使用吗

出0入0汤圆

发表于 2010-11-14 17:14:37 | 显示全部楼层
Gorgon Meducer 傻孩子:
        傻孩子大侠,我很高兴把你的菜单结构弄懂了,非常非常的感谢你无私的帮助!是你让我从无知到有知!从迷惘到开明,再次表示衷心的感谢!
        但是我碰到的一个问题是:我想实现一个3、4级或者更多级的菜单,不知道该怎么写!这个问题困扰了我很久也没办法解决!穷途之中再次想起了你!尽管很不好意思打扰大侠!不知道大侠能不能再在百忙之中抽出一点指点一二呀!多多感谢!!!!

出0入0汤圆

发表于 2010-11-15 15:48:40 | 显示全部楼层
Gorgon Meducer 傻孩子:
       大侠这么快就回复我了, 真是太感谢了,其实我也知道你菜单的意思了,多级的话就是再增加几个菜单结构型数组,也就是把这个链表作长一点 但是我我感觉那样的话,内存用起来就很可观了,然后我又仔细看了《一个占用内存极小的菜单实现》的那个例子,他用查索引号找对应的函数的方法,这样的话, 内存是少了, 但是改动就又很大。更何况我只是能看懂两位大侠的意思,照搬还可以,要我自己想又想不出好的办法来解决这个问题, 再三厚着脸皮来了,不知道大侠还能指点一二么?多多谢谢!!!

出0入0汤圆

发表于 2010-11-15 16:24:08 | 显示全部楼层
想用白菜的价来买肉是买不到的

出0入0汤圆

发表于 2010-11-16 08:40:24 | 显示全部楼层
【20楼】 liaowei
        没办法!菜鸟的很!阁下如有好的建议!还望不吝赐教!本人不胜感激啊!

出0入0汤圆

发表于 2010-12-30 14:37:24 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-9-9 14:04:58 | 显示全部楼层
学习贴,顶一个。

出0入0汤圆

发表于 2011-10-15 19:25:14 | 显示全部楼层
MARK

出0入0汤圆

发表于 2012-10-20 23:47:12 | 显示全部楼层
学习贴,顶一个。

出0入296汤圆

发表于 2012-10-22 10:39:21 | 显示全部楼层
liaogang1314 发表于 2010-11-15 15:48
Gorgon Meducer 傻孩子:
       大侠这么快就回复我了, 真是太感谢了,其实我也知道你菜单的意思了,多级 ...

原则上菜单都应该保存在__flash里面……这样对SRAM消耗就没有那么大。

出0入0汤圆

发表于 2012-12-17 15:19:24 | 显示全部楼层
菜单需要

出0入0汤圆

发表于 2012-12-23 21:27:36 | 显示全部楼层
一直关注大侠,有问题要问:
1,在计算机层次上,汇编语言带来了什么抽象?
2,在汇编语言上,C及其编译器带来了什么抽象?
3,C++等面向对象带来了什么抽象?

出0入0汤圆

发表于 2013-4-25 16:22:12 | 显示全部楼层
mark。自己一开始做过多级菜单。但不是很好。
“树”,回家后也好好研究一下。

出0入0汤圆

发表于 2014-10-18 23:19:43 | 显示全部楼层
发现一个东西:多级菜单。。。打开了一扇门。。。

出0入0汤圆

发表于 2014-10-23 16:34:40 | 显示全部楼层
谢谢分享            

出0入296汤圆

发表于 2014-10-23 23:12:50 | 显示全部楼层
New_Bird_De_Bug 发表于 2012-12-23 21:27
一直关注大侠,有问题要问:
1,在计算机层次上,汇编语言带来了什么抽象?
2,在汇编语言上,C及其编译器 ...

概念一直在变,只有追求偷懒的“抽象”是不变的。

出0入0汤圆

发表于 2014-11-22 16:36:11 | 显示全部楼层
New_Bird_De_Bug 发表于 2012-12-23 21:27
一直关注大侠,有问题要问:
1,在计算机层次上,汇编语言带来了什么抽象?
2,在汇编语言上,C及其编译器 ...

我的看法是:
1.机器指令到汇编语言,从很难记住的01代码成了容易记住和书写的助记符。对应关系大约是一一对应(不考虑宏)。
2.汇编到C,一次抽象,对应关系是一句C代码对应多个汇编代码。而且C语言更符合人的思维习惯,不用考虑那么多底层细节了(交给编译器来做)。
3.C到C++,编程思想的改变。C和汇编都是面向过程的编程语言,其实本质上单个CPU执行代码是串行的,即一句一句执行,我们写程序之前分析问题,也是想着怎么一步一步解决这个问题,然后写成编程语言。这是你一个人在做事情。
而面向对象,在分析问题的时候,只需要把问题分解为一个一个的"对象",每个对象就像是一个一个的人,可以"做一些事情",有一些"口袋",里面装着一些东西,现在,你需要解决的问题,由这一群人来共同解决。
但是本质上,单个CPU只能一步一步来执行指令,想让一个人变成一群人(不是人格分裂),只要这个人不停的在这群人的身份之间转变就行,一会是这个,一会是另一个人(操作系统完成这个转变的任务,还可以写成状态机的形式)。


第一次交流,不对的地方还请各位老师指正!

——大三狗。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-3 09:44

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表