zyzoe2003 发表于 2012-3-31 15:05:39

请教傻孩子,触摸屏菜单问题。

傻孩子:
   你好,首先对你表示感激之情。我已经将你的菜单系统移植到LCD上,我感觉这个菜单很好理解。但是最近我将它使用到触摸屏上,并将结构做了点调整,将原来显示条目改成页面显示函数 unsigned char *DisplayString--->void (*DisplayPage)();
,但还是感觉使用那个结构有点不合理,我目前只使用到void (*DisplayPage)(); void (*Subs)(); 这两个属性操作。对于其他三个成员几乎没有操作。我将触摸屏上的每个按键操作都准确定义到返回或进入的画面及操作函数。虽然已经完成基本功能,但是总让我感觉有点笨拙,不知你在触摸屏菜单上有没有更高明的方法,希望能得到你关于触摸屏菜单方面的指点,谢谢!

Gorgon_Meducer 发表于 2012-4-2 00:02:41

本帖最后由 Gorgon_Meducer 于 2012-4-2 00:04 编辑

对于触摸屏,完全用链表似乎会好一点。其实触摸屏的菜单往往灵活度较大,用链表的好处是,可以动态修改前后菜单项的关系,比如,经常被用到的菜单项会逐渐被挪到前面……不知道这样说有没有给你一些思路和灵感。

zyzoe2003 发表于 2012-4-5 10:47:36

非常感谢你的回答,你说的:链表能动态修改前后菜单项的关系,这点就是我对触摸屏上的每个按键操作都准确定义到返回或进入的画面及操作函数感觉到笨拙的解决方法,谢谢你的回复!我将考虑下链表,听君一席话,胜读十年书!

Gorgon_Meducer 发表于 2012-4-5 19:52:38

zyzoe2003 发表于 2012-4-5 10:47 static/image/common/back.gif
非常感谢你的回答,你说的:链表能动态修改前后菜单项的关系,这点就是我对触摸屏上的每个按键操作都准确定 ...

能帮上忙就好。对于触摸菜单,还可以在菜单项里面加入一个UserDraw函数指针,用于自定义某些特殊的菜单项外观,如果UserDraw是NULL,就用默认的绘制方式,如果不为NULL,就调用这个UserDraw,并传递一个rectangle范围进去——让对应的绘制程序在这个rectangle里面绘制自己的外观。当然,这种处理方式已经有点复杂了。不过对轻量级GUI还是很有用的技巧。

GZZXB 发表于 2012-4-6 08:26:26

某日,出版社编辑抓到了我
编辑:你可以筹备《深入浅出AVR单片机》第二版了
我: 我动大手术可以不?
编辑:不动你卖得掉?
我: ……
期待第二版,不要动大手术了,来个续集或加强版。

wanglingyanj 发表于 2012-5-5 10:28:50

傻孩子:
      你好,想请你帮一下忙,你能不能传一个关于触摸屏触摸菜单的代码给我参考一下,谢谢!

wanglingyanj 发表于 2012-5-5 14:01:36

你好,你已经研究了触摸屏的菜单,能不能指点一下触摸屏菜单编程思路呀!
{:smile:}

Gorgon_Meducer 发表于 2012-5-5 15:00:43

wanglingyanj 发表于 2012-5-5 14:01 static/image/common/back.gif
你好,你已经研究了触摸屏的菜单,能不能指点一下触摸屏菜单编程思路呀!
...

具体怎样一个硬件环境呢?主要是了解下你理想中用户可以作的操作。

wanglingyanj 发表于 2012-5-5 16:34:59

谢谢傻孩子这么快的恢复,我是在uc/GUI下,触摸芯片ADS7843,触摸屏上显示菜单,例如示波器的界面,第一级菜单上有同步模式、水平灵敏度、垂直灵敏度等,然后触摸一级菜单,如同步模式,就会出现下拉菜单的正常模式、随机模式、单次模式等,若触摸二级菜单选择正常模式,正常模式就会在覆盖一级菜单,显示是同步模式,下拉菜单消失,请求傻孩子指点,谢谢!

stmlt 发表于 2012-5-25 15:07:05

Gorgon_Meducer 发表于 2012-5-5 15:00 static/image/common/back.gif
具体怎样一个硬件环境呢?主要是了解下你理想中用户可以作的操作。

你好!请问一下程序在单片机上裸奔能实现触摸屏菜单的功能吗?我没学过ucos操作系统和ucgui,我用的是stm32单片机,ad7843触摸芯片,具体该怎么实现呢?有没有类似的程序学习一下,希望你能指点一下,谢谢

Gorgon_Meducer 发表于 2012-5-25 20:38:40

stmlt 发表于 2012-5-25 15:07 static/image/common/back.gif
你好!请问一下程序在单片机上裸奔能实现触摸屏菜单的功能吗?我没学过ucos操作系统和ucgui,我用的是stm ...

菜单程序通常和是否使用操作系统无关。但是如果考虑菜单环境下还要抱持绝对的多任务环境,就需要特别的考虑了。一般用操作系统的环境下实现起来比较简单;在裸机环境下用状态机可以实现多任务环境下的菜单。例子程序,我手边没有现成的,你可以在论坛上找找,记得有的。

stmlt 发表于 2012-6-5 21:49:06

楼主你好!我最近也在研究触摸屏菜单界面,我的qq:843182364,能加一下,希望你能指点一下,本人还是菜鸟,很多地方还不懂,谢谢!

stmlt 发表于 2012-6-6 09:21:04

Gorgon_Meducer 发表于 2012-5-25 20:38 static/image/common/back.gif
菜单程序通常和是否使用操作系统无关。但是如果考虑菜单环境下还要抱持绝对的多任务环境,就需要特别的考 ...

谢谢Gorgon_Meducer傻孩子的详细解答,我最近看了你那菜单界面的构架,比网上其它很多的菜单程序明了、通俗易懂,但是你那个菜单程序:当执行了子菜单--功能函数之后,它就自动返回子菜单界面了,怎么样在执行功能函数之后停留在那个界面,点返回后才退到子菜单界面。

Gorgon_Meducer 发表于 2012-6-6 14:44:58

stmlt 发表于 2012-6-6 09:21 static/image/common/back.gif
谢谢Gorgon_Meducer傻孩子的详细解答,我最近看了你那菜单界面的构架,比网上其它很多的菜单程序明了、通 ...

在sub函数里面做文章就可以了哈。

zyzoe2003 发表于 2012-6-8 13:50:48

sub函数里面里面设置循环,只有某个条件满足后才返回即可。

zyzoe2003 发表于 2012-6-8 13:56:51

wanglingyanj 发表于 2012-5-5 14:01 static/image/common/back.gif
你好,你已经研究了触摸屏的菜单,能不能指点一下触摸屏菜单编程思路呀!
...

目前也主要是基于傻孩子菜单,也只是简单实验了一下,具体也没有实现{:loveliness:} ,最近事情很多,也就没研究了,还没有很好方法,我也是菜鸟一个。不过你可以看一下酷系统的菜单。

cb1470 发表于 2012-7-16 15:58:49

求Gorgon_Meducer傻孩子这位高手的菜单架构,最近要做个项目,菜单想做得好看点的,但是不知道用51,还有12864可不可以做一个像样点的菜单

zyzoe2003 发表于 2012-7-16 16:05:18

Menu.h
-------------------------------

#ifndef __MENU_h__
#define __MENU_h__
#include "Functions.h"
/****************************************************
* 支持库说明:提供了使用菜单的基本数据结构          *
* 作者:      傻孩子                              *
* 日期:      2005年6月9日                        *
****************************************************/

/**********************
*    目录结构体定义   *
**********************/
struct MenuItem
{
    short MenuCount;
    char *DisplayString;
    void (*Subs)();
    struct MenuItem *ChildrenMenus;
    struct MenuItem *ParentMenus;
}Null;

void NullSubs(void)
{
}



/****************************************************
*   使用说明:                                    *
*      要定义一个菜单,需要做以下几步工作         *
*      1、定义一个结构体数组                        *
*      2、如果这个菜单是子菜单,那么把上级菜单的    *
*         *ChildrenMenus指针指向该数组的首地址,   *
*         并且设置ParentMenus为上层目录的地址       *
*      3、如果这个菜单是跟菜单,那么直接将MenuPoint *
*         指针指向该数组的首地址                  *
*      4、通过写一个函数为该数组的每一个元素初始化*
*      5、如果菜单项是最终选项,那么将*ChildrenMenus*
*         置为NULL,将函数指针*Subs指向实现功能的   *
*         函数。                                    *
****************************************************/


struct MenuItem MainMenu;
struct MenuItem TimeMenu;
struct MenuItem VoiceMenu;
struct MenuItem RobotMenu;
struct MenuItem FlashMenu;

/***********************
*   函 数 声 明 区   *
***********************/
void MainMenuInit(void);
void TimeMenuInit(void);
void VoiceMenuInit(void);
void RobotMenuInit(void);
void FlashMenuInit(void);

/**************************************************************
*函数说明:Flash处理目录初始化函数                        *
**************************************************************/
void FlashMenuInit(void)
{
    FlashMenu.MenuCount = 5;
    FlashMenu.DisplayString = "Flash Record";
    FlashMenu.Subs = FlashRecord;
    FlashMenu.ChildrenMenus = &Null;
    FlashMenu.ParentMenus = MainMenu;
   
    FlashMenu.MenuCount = 5;
    FlashMenu.DisplayString = "      Play      ";
    FlashMenu.Subs = FlashPlay;
    FlashMenu.ChildrenMenus = &Null;
    FlashMenu.ParentMenus = MainMenu;
   
    FlashMenu.MenuCount = 5;
    FlashMenu.DisplayString = "      Pause   ";
    FlashMenu.Subs = FlashPause;
    FlashMenu.ChildrenMenus = &Null;
    FlashMenu.ParentMenus = MainMenu;
   
    FlashMenu.MenuCount = 5;
    FlashMenu.DisplayString = "Flash Delete";
    FlashMenu.Subs = FlashDelete;
    FlashMenu.ChildrenMenus = &Null;
    FlashMenu.ParentMenus = MainMenu;
   
    FlashMenu.MenuCount = 5;
    FlashMenu.DisplayString = "      Back      ";
    FlashMenu.Subs = NullSubs;
    FlashMenu.ChildrenMenus = MainMenu;
    FlashMenu.ParentMenus = MainMenu;
}

/**************************************************************
*函数说明:机器人控制目录初始化函数                         *
**************************************************************/
void RobotMenuInit(void)
{
    RobotMenu.MenuCount = 5;
    RobotMenu.DisplayString = "   TurnLeft   ";
    RobotMenu.Subs = RobotTurnLeft;
    RobotMenu.ChildrenMenus = &Null;
    RobotMenu.ParentMenus = MainMenu;
   
    RobotMenu.MenuCount = 5;
    RobotMenu.DisplayString = "   Turn Right   ";
    RobotMenu.Subs = RobotTurnRight;
    RobotMenu.ChildrenMenus = &Null;
    RobotMenu.ParentMenus = MainMenu;
   
    RobotMenu.MenuCount = 5;
    RobotMenu.DisplayString = "    GoAhead   ";
    RobotMenu.Subs = RobotGoAhead;
    RobotMenu.ChildrenMenus = &Null;
    RobotMenu.ParentMenus = MainMenu;
   
    RobotMenu.MenuCount = 5;
    RobotMenu.DisplayString = "   Go Back    ";
    RobotMenu.Subs = RobotGoBack;
    RobotMenu.ChildrenMenus = &Null;
    RobotMenu.ParentMenus = MainMenu;
   
    RobotMenu.MenuCount = 5;
    RobotMenu.DisplayString = "      Back      ";
    RobotMenu.Subs = NullSubs;
    RobotMenu.ChildrenMenus = MainMenu;
    RobotMenu.ParentMenus = MainMenu;
   
}

/**************************************************************
*函数说明:声音处理目录初始化函数                           *
**************************************************************/
void VoiceMenuInit(void)
{
    VoiceMenu.MenuCount = 5;
    VoiceMenu.DisplayString = "Voice Record";
    VoiceMenu.Subs = VoiceRecord;
    VoiceMenu.ChildrenMenus = &Null;
    VoiceMenu.ParentMenus = MainMenu;
   
    VoiceMenu.MenuCount = 5;
    VoiceMenu.DisplayString = "      Play      ";
    VoiceMenu.Subs = Play;
    VoiceMenu.ChildrenMenus = &Null;
    VoiceMenu.ParentMenus = MainMenu;
   
    VoiceMenu.MenuCount = 5;
    VoiceMenu.DisplayString = "      Pause   ";
    VoiceMenu.Subs = Pause;
    VoiceMenu.ChildrenMenus = &Null;
    VoiceMenu.ParentMenus = MainMenu;
   
    VoiceMenu.MenuCount = 5;
    VoiceMenu.DisplayString = "Voice Delete";
    VoiceMenu.Subs = VoiceDelete;
    VoiceMenu.ChildrenMenus = &Null;
    VoiceMenu.ParentMenus = MainMenu;
   
    VoiceMenu.MenuCount = 5;
    VoiceMenu.DisplayString = "      Back      ";
    VoiceMenu.Subs = NullSubs;
    VoiceMenu.ChildrenMenus = MainMenu;
    VoiceMenu.ParentMenus = MainMenu;
}

/**************************************************************
*函数说明:时间设定子目录初始化                           *
**************************************************************/
void TimeMenuInit(void)
{
    TimeMenu.MenuCount = 4;
    TimeMenu.DisplayString = "    Time Set    ";
    TimeMenu.Subs = TimeSet;
    TimeMenu.ChildrenMenus = &Null;
    TimeMenu.ParentMenus = MainMenu;
   
    TimeMenu.MenuCount = 4;
    TimeMenu.DisplayString = "    Date Set    ";
    TimeMenu.Subs = DateSet;
    TimeMenu.ChildrenMenus = &Null;
    TimeMenu.ParentMenus = MainMenu;
   
    TimeMenu.MenuCount = 4;
    TimeMenu.DisplayString = "    AlertSet    ";
    TimeMenu.Subs = AlertSet;
    TimeMenu.ChildrenMenus = &Null;
    TimeMenu.ParentMenus = MainMenu;
   
    TimeMenu.MenuCount = 4;
    TimeMenu.DisplayString = "      Back      ";
    TimeMenu.Subs = NullSubs;
    TimeMenu.ChildrenMenus = MainMenu;
    TimeMenu.ParentMenus = MainMenu;
   
}

/**************************************************************
*函数说明:根目录初始化                                     *
**************************************************************/
void MainMenuInit(void)
{
   MainMenu.MenuCount = 3;
   MainMenu.DisplayString = "    Time Set    ";
   MainMenu.Subs = NullSubs;
   MainMenu.ChildrenMenus = TimeMenu;
   MainMenu.ParentMenus = &Null;

   MainMenu.MenuCount = 3;
   MainMenu.DisplayString = "Voice Center";
   MainMenu.Subs = NullSubs;
   MainMenu.ChildrenMenus = VoiceMenu;
   MainMenu.ParentMenus = &Null;
/*
   MainMenu.MenuCount = 3;
   MainMenu.DisplayString = "Robot Control ";
   MainMenu.Subs = NullSubs;
   MainMenu.ChildrenMenus = RobotMenu;   
   MainMenu.ParentMenus = &Null;
*/      
   MainMenu.MenuCount = 3;
   MainMenu.DisplayString = "Flash Option";
   MainMenu.Subs = NullSubs;
   MainMenu.ChildrenMenus = FlashMenu;      
   MainMenu.ParentMenus = &Null;

}

#endif

Function.h
------------------------------

#ifndef __FUNCTIONS_h__
#define __FUNCTIONS_h__
/****************************************************
* 支持库说明:系统菜单功能文件宏                  *
* 日期:      2005年6月9日                        *
****************************************************/
    #include "TimeSet.h"
    #include "VoiceCenter.h"
    #include "RobotControl.h"
    #include "FlashOption.h"

/*--------------------------------
   上面包含的头文件里面包含了菜单
   功能选项所要调用的函数。
--------------------------------*/
#endif


main.c
-----------------------------

#include "GRAPH_Command.h"
#include "Functions.h"
#include "Menu.h"

/***********************
*   按键功能键宏定义   *
***********************/
# define UP      0
# define Down      4
# define Enter   5
# define Esc       1
# define Reset   2

/***********************
*   全局变量声明区   *
***********************/

   
    struct MenuItem (*MenuPoint) = MainMenu;
    short DisplayStart = 0;
    short UserChoose = 0;
    short DisplayPoint = 0;
    short MaxItems;   


/*****************************
* Struct MenuItem:         *
*    short MenuCount;      *
*    char *DisplayString;    *
*    void (*Subs)();         *
*    MenuItem *ChildrenMenus;*
*    MenuItem *ParentMenus;*
*****************************/

/***********************
*   函 数 声 明 区   *
***********************/
extern void ClearWatchDog();
void MenuInitialation(void);
void SystemInitialation(void);
void ShowMenu(void);
short GetKeyNum(void);

/**************************************************************
*函数说明:系统初始化函数                                 *
**************************************************************/
void SystemInitialation(void)
{
Init_sys();   
Enable_LCD();                   //初始化字库      函数定义在
MenuInitialation();               //初始化菜单
GRAPH                           //图形初始化
}

/**************************************************************
*函数说明:目录初始化函数                                 *
**************************************************************/
void MenuInitialation(void)
{
    MainMenuInit();
    TimeMenuInit();
    VoiceMenuInit();
    RobotMenuInit();
    FlashMenuInit();
}

/**************************************************************
*函数说明:目录显示函数                                     *
**************************************************************/
void ShowMenu(void)
{
    short n = 0;

    MaxItems = MenuPoint.MenuCount;
    DisplayPoint = DisplayStart;
if (MaxItems >= 4)
{
   for (n = 0;n<4;n++)
   {
                  
         LOCATE(n+1,1);
         PRINT(MenuPoint.DisplayString);
         
         if ((DisplayPoint) == UserChoose)
             {
               BOX(1,n*16+1,126,(n+1)*16-2,1,1);
             }
         
             DisplayPoint +=1;
             if ((DisplayPoint) == (MaxItems))
             {
               DisplayPoint = 0;
             }
   }
}
else
{
   for (n = 0;n<MaxItems;n++)
   {
                  
         LOCATE(n+1,1);
         PRINT(MenuPoint.DisplayString);
         
         if ((DisplayPoint) == UserChoose)
             {
               BOX(1,n*16+1,126,(n+1)*16-2,1,1);
             }
         
             DisplayPoint +=1;
             if ((DisplayPoint) == (MaxItems))
             {
               DisplayPoint = 0;
             }
         
   }
}
//BOX(0,0,127,63,2,2);
}

/**************************************************************
*函数说明:获得键值函数                                     *
**************************************************************/
short GetKeyNum(void)
{
    short TempKeyNum = 0;
TempKeyNum = F_Key_Scan();       //获取按键值
*P_IOA_Dir = 0x01ff;
*P_IOA_Attrib = 0x01ff;      
*P_IOA_Data = 0x01ff;
   
return TempKeyNum;

}

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

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


}


jinquan123 发表于 2012-7-30 19:51:39

牛人~{:handshake:}

chengying 发表于 2012-9-29 11:48:27

谢谢,参考一下,不错

gdmgb520 发表于 2012-10-31 15:13:41

要好好学习下

付新辉 发表于 2012-12-17 15:03:28

链表可能是新路,尝试一下

king1314 发表于 2014-1-23 11:15:24

mark下 ,傻孩子牛啊

lizheng2013 发表于 2014-2-13 11:19:25

弱弱问下,在菜单末端怎么通过按键(UP /DOWN/ENTER/ESC)进行一个变量的调节呢?如:音量=0——255的设置??调节时指针不用死等在那里吧?

zyzoe2003 发表于 2014-2-14 16:21:09

lizheng2013 发表于 2014-2-13 11:19
弱弱问下,在菜单末端怎么通过按键(UP /DOWN/ENTER/ESC)进行一个变量的调节呢?如:音量=0——255的设置? ...

UP /DOWN是进行页面中条目进行选择,ENTER/ESC是进行父子菜单切换,我为了避免混淆,页面末端进行修改是用+/-键进行变量修改。你想进行复用,还需做些考虑。调节时指针不用死等在那里吧?不太清楚你说的是什么指针。

lizheng2013 发表于 2014-2-15 13:28:34

谢楼主回复“…页面末端进行修改是用+/-键进行变量修改…想进行复用,还需做些考虑……”就这里不知道怎么用:当ENTER后,或进入 SUB函数-->调节某变量:如:音量=0——255的设置?,"还需做些考虑" 就这想了很久也没想到好的方法呢?

mcu_lover 发表于 2014-2-15 13:42:50

lizheng2013 发表于 2014-2-15 13:28
谢楼主回复“…页面末端进行修改是用+/-键进行变量修改…想进行复用,还需做些考虑……”就这里不知道怎么 ...

当然是用万能的状态机了

void sub(void)
{
   switch(keyValue)
    {
         case KEY_UP:
            AdjustVarUpLimit(255, &var);
         break;

         case KEY_DOWN:
            AdjustVarDownLimit(0, &var);            
         break;
    }
    //update display
    UpdateDisplay();
}

注意,主程序结构也要做成状态机式非阻塞模型。

stevenniu500 发表于 2014-6-17 16:47:06

好东西,标记一下。

hfjydq 发表于 2014-6-20 13:11:32

请问傻孩子的那个菜单程序的链接在哪

mafeimafei 发表于 2014-11-20 21:58:43

遇到问题,来学习地。
页: [1]
查看完整版本: 请教傻孩子,触摸屏菜单问题。