xf331785508 发表于 2013-12-5 16:04:43

我的串口屏如何响应UI中的按钮,求个思路?

如图,做的串口屏,做了UI按钮,却一直没有想到好的响应方式,代码很傻瓜的去读坐标,比坐标,再判断按键,再更新显示框,不知道有没有好的按钮响应处理思想,没太接触过操作系统,看了看WINDOWS 的消息机制,但好像套用起来一是思维还不太习惯,二是代码量好像很大,还要很好的结构体封装,好的架构才能实现。   
-------------------------分割线-------------------------------
图片手机拍的,不太好看。
有好的思想的,交流下。

xf331785508 发表于 2013-12-5 16:11:10

沉得好快。呵呵,一看大部分资讯信息啊。自己再顶一下吧。

Gorgon_Meducer 发表于 2013-12-5 17:52:04

本帖最后由 Gorgon_Meducer 于 2013-12-5 18:20 编辑

简单来说这么处理的

屏幕上的按钮和文本框都是一个矩形区域,你可以定义一个数据结构

typedef struct {
    int nTop;
    int nLeft;
    int nWidth;
    int nHeigh;
}rect_t;

然后为屏幕上所有的对象串起来:

typedef struct control_t control_t

struct control_t {
    rect_t tWindow;
    control_t *ptNext;
};

static control_t *s_ptControls = NULL;

control_t *get_controls(void)
{
    return s_ptControls;
}


每次获得触摸信息以后,通过这个链表来依次扫描看看落在哪个区域里面了,如果落入了,你懂得。
另外,实际上这个链表还可以作为刷新的顺序,GUI术语上叫做Z-Order。你可以把它做成双链表,
这样还可以实现windows上窗体覆盖,激活的效果。

希望对你有所帮助。这里提到的只是最小实现,复杂一点的窗体结构还可以在control_t里面加入
更多的元素,比如如何绘制这个窗体啊之类的信息,窗体是否被按下了啊,是否处于激活状态啊,
文本信息是什么啊……,另外如果把窗体做成一个容器……你懂的。

事件处理其实并不复杂,下面以简单的Click事件为例子:
首先,你要定义一个事件处理程序的函数原型

typedef struct {
    int x,
    int y
    //其它你想附加的信息
}key_event_t;

typedef bool click_event_t(key_event_t *ptEvent);


然后更新control_t类:

struct control_t {
    rect_t tWindow;
    control_t *ptNext;

    click_event_t *fnClickEvent;
};


增加一个事件处理程序的注册函数


//! 小把戏,你懂的
#define this    (*ptThis)

bool control_register_click_event_handler(control_t *ptThis, click_event_t *fnHandler)
{
    if (NULL == ptThis || NULL == fnHandler) {
      return false;
    }
   
    this.fnClickEvent = fnHandler;

    return true;
}


最后我们就可以编写一个程序,根据输入的x,y来触发对应的按键的程序了:

bool controls_check_click_event(control_t *ptThis, int x, int y)
{
    if (NULL == ptThis) {
      return false;
    }

    //! 搜索链表
    do {
      if (check_is_point_in_rect(&this.tWindow, x, y)) {
             //! 点落在矩形里面了
             if (NULL != this.fnClickEvent) {
                  //! 调用相应的消息处理程序
                  key_event_t tEvent = {x, y};
                  this.fnClickEvent(&tEvent);
                  return true;
             }
      }
      
      //! 继续搜索
      ptThis = this.ptNext;
    } while(NULL != ptChain);

    //! 如果运行到这里,说明什么都没有搜索到
    return false;
}



zhexuejia 发表于 2013-12-5 18:21:17

楼上高端大气上档次啊

MINI2440 发表于 2013-12-5 18:36:25

Gorgon_Meducer 发表于 2013-12-5 17:52
简单来说这么处理的

屏幕上的按钮和文本框都是一个矩形区域,你可以定义一个数据结构


够详细。。新书出了没

syauxwm 发表于 2013-12-5 19:28:00

霸气,好好看看,

justdomyself 发表于 2013-12-5 19:37:18

霸气~~~~~~~~~~~~~~

binaimei2007 发表于 2013-12-5 19:38:42

学习大神的方法!!!

Gorgon_Meducer 发表于 2013-12-5 23:14:10

MINI2440 发表于 2013-12-5 18:36
够详细。。新书出了没

还没…以我这种王婆卖瓜的个性,出了还不满世界的吹~

leicai05 发表于 2013-12-6 08:22:21

我是来听课的。

Excellence 发表于 2013-12-6 09:05:22

{:victory:}{:victory:}{:victory:}

kalo425 发表于 2014-1-1 00:47:02

Gorgon_Meducer 发表于 2013-12-5 17:52
简单来说这么处理的

屏幕上的按钮和文本框都是一个矩形区域,你可以定义一个数据结构


{:victory:}

meirenai 发表于 2014-1-6 00:34:00

看一下            

bbglx 发表于 2014-5-24 09:06:11

默默收藏

znsword 发表于 2014-8-7 02:44:06

强悍,收藏一下。

xf331785508 发表于 2016-6-7 16:50:58

本帖最后由 xf331785508 于 2016-6-7 17:04 编辑

根据傻孩子的砖,我斗胆晒一下我的糟玉。以飨坛友。


#include <string.h>
#include "TSP.h"
#ifndef   COUNTOF
#define   COUNTOF(__a)((sizeof((__a)))/(sizeof(*(__a))))
#endif

/*
gTouchXYUpdateFlag was changed in interrupt function
*/
volatile bool gTouchXYUpdateFlag = FALSE;
// Temporary save datas from touch screen to buffer
u8   gReceiveBuffer = {0};
u32gRxCounter = 0;


/* Retangle assign */
static Rectangle_Typedef*Rectangle_TypedefAssign(Rectangle_Typedef *pRect, u16 left, u16 top, u16 width, u16 height)
{
        if( NULL == pRect )
        {
                return NULL;
        }
        pRect->nLeft   = left;
        pRect->nTop    = top;
        pRect->nWidth= width;
        pRect->nHeight = height;
        return pRect;
}

/* Control block assign for each element */
static Control_Typedef *Control_TypedefAssign
(Control_Typedef   *pCtrl,
Rectangle_Typedef   *pWindow,
Control_Typedef   *pNext,
ClickEvent          *pfn,
u32               indexOf,
u8                  captionNums,
char                *str,
u32               reserve)
{
        if( NULL == pCtrl )
        {
                return NULL;
        }
        pCtrl->tWindow      = pWindow;
        pCtrl->ptNext       = pNext;
        pCtrl->fnClickEvent = pfn;
        pCtrl->index      = indexOf;
        pCtrl->charNums   = captionNums;
        pCtrl->btnCaption   = str;
        pCtrl->timeOfCycle= reserve;
        return pCtrl;
}

/* Translate the location of the button which was pressed
* from USART interface buffer. */
TOUCH_XY AnalysisTouchXY(void)
{
        u8 i = 0;
        TOUCH_XY touchXY = {0, 0};
        if( gTouchXYUpdateFlag )
        {
                for(i = 0; i < COUNTOF(gReceiveBuffer); i++)
                {
                        if((gReceiveBuffer == CMD_HEAD) && (gReceiveBuffer == RETURN_TOUCHSCREEN_XY))
                        {
                                touchXY.x = (u16)((gReceiveBuffer << 8) | gReceiveBuffer);
                                touchXY.y = (u16)((gReceiveBuffer << 8) | gReceiveBuffer);
                                gTouchXYUpdateFlag = FALSE;
                                memset(gReceiveBuffer, 0, sizeof(gReceiveBuffer));
                                gRxCounter = 0;
                                break;
                        }
                }
        }
        return touchXY;
}

/* According the location to return the index of button retangle which was pressed. */
u8 RtnTouchScreenRst(TOUCH_XY tp, const RETANGLE_AREA *pArea)
{
        u8 equivalentKey = KEY_NONE;
       
        if( NULL == pArea )
        {
                return equivalentKey;
        }
        if((tp.x >= (pArea->sx)) && (tp.x <= (pArea->ex)) &&
           (tp.y >= (pArea->sy)) && (tp.y <= (pArea->ey)))
        {
                equivalentKey = pArea->areaNo;
        }
        return equivalentKey;
}

/* To check the range of location */
bool CheckPointinRectangle(Rectangle_Typedef *ptRect, u16 x, u16 y)
{
        if( NULL == ptRect )
        {
                return FALSE;
        }
        if((x >= ptRect->nLeft) && (x <= (ptRect->nLeft + ptRect->nWidth)))
        {// x is in the range
                if((y >= ptRect->nTop) && (y <= (ptRect->nTop + ptRect->nHeight)))
                {// y is in the range
                        return TRUE;
                }
                else{
                        return FALSE;
                }
        }
        else{
                return FALSE;
        }
}

/* To find the correct button and call back the right handler which was defined. */
s32 ControlsCheckClickEvent(Control_Typedef *ptThis, KEY_EVENT_Typedef *ptKeyValue)
{
    if ((NULL == ptThis) || (NULL == ptKeyValue))
        {
      return FAULT;
    }
    do {
                if (CheckPointinRectangle((ptThis->tWindow), ptKeyValue->x, ptKeyValue->y))
                {
                        if ( NULL != ptThis->fnClickEvent )
                        {
                                return (ptThis->fnClickEvent(ptKeyValue, &(ptThis->index)));
                        }
                        else{
                                return FAULT;
                        }
                }
      ptThis = ptThis->ptNext;
    } while(NULL != ptThis);
    return FAULT;
}


/* Button's retangle drawing */
static voidAppLCM_Buttons(u8 btnNums, bool isBtnDraw, Rectangle_Typedef *ptRect, Control_Typedef *ptCtrl)
{
        register u8 i = 0;
       
        if( NULL == ptRect||NULL == ptCtrl )
        {
                return NULL;
        }
        if( isBtnDraw )
        {
                for(i = 0; i < btnNums; i++)
                {
                        LCM_ButtonDraw((ptRect + i)->nLeft,(ptRect + i)->nTop,
                                       (ptRect + i)->nWidth, (ptRect + i)->nHeight,
                                                   BUTTON_COLOR,
                                                   (ReturnCharacterNumber((ptCtrl + i)->btnCaption) >> 1),
                                                   (ptCtrl + i)->btnCaption);
                }
        }
}

/* According the index of key in keyboard to return the correct retangle's location. */
static TOUCH_XY Convert2XY(u16 keyValue, Control_Typedef*ptThis)
{
        TOUCH_XYrtnXY = {0, 0};
       
        if( NULL == ptThis )
        {
                return rtnXY;
        }
    do {   
      if ( KEY == ptThis->index )
                {
                        rtnXY.x = ptThis->tWindow->nLeft + 1;
                        rtnXY.y = ptThis->tWindow->nTop+ 1;
                        KEY = KEY_NONE;
                        return rtnXY;               
      }
          ptThis = ptThis->ptNext;
    } while(NULL != ptThis);
    return rtnXY;
}




void AppLCM_UserInterfaceProcess(u8 btnNums, bool isBtnDraw, Rectangle_Typedef *ptRect, Control_Typedef *ptCtrl)
{

        boolisReturn = TRUE;
        u32   counter = 0;
        KEY_EVENT_Typedef keyEvent = {0,0};
       
        if( NULL == ptCtrl||NULL == ptRect )
        {
                return;
        }
        KEY = KEY_NONE;
        AppLCM_Buttons(btnNums, isBtnDraw, ptRect, ptCtrl);       
        if( ((ptCtrl->timeOfCycle) == 0) || ((ptCtrl->timeOfCycle & 0xFFFF0000) != 0) ){
                ptCtrl->timeOfCycle = 0xFFFF;
        }
        do
        {
                if(KEY != KEY_NONE){
                        gTchLoc = Convert2XY(KEY, ptCtrl);
                        KEY = KEY_NONE;          
                }
                else{
                        gTchLoc = AnalysisTouchXY();
                }
                keyEvent.x = gTchLoc.x;
                keyEvent.y = gTchLoc.y;
                delay_ms(50);
                switch(ControlsCheckClickEvent(ptCtrl, &keyEvent))
                {
                        case QUIT:       
                                        isReturn = FALSE;
                                        ptCtrl->timeOfCycle &= 0x0000FFFF;             
                                        ptCtrl->timeOfCycle |= (keyEvent.x << 16);
                        break;
                        case CYCLE:       
                        break;
                        case REDRAW:
                                        counter = 0;
                                        AppLCM_Buttons(btnNums, isBtnDraw, ptRect, ptCtrl);
                        break;
                        case FAULT:       
                        break;
                        default:
                        break;
                }
                counter++;
        }while( (isReturn) && (counter < (ptCtrl->timeOfCycle)));
}



static s32 AppLCM_ComSetHandler(KEY_EVENT_Typedef *ptEvent, u32 *btnNo)
{
        ptEvent = ptEvent;
        switch(*btnNo)
        {
                case NO:
                        return QUIT;
                case 1:
                        Process1();
                        return CYCLE;
                case 2:
                        Process2();
                        return REDRAW;
                case 3:
                        Process3();
                        return CYCLE;
                default:
                return CYCLE;
        }
}


voidAppLCM_ComSetSubMenu(void)
{
        Rectangle_Typedef rect = {0};
        Control_Typedef ctrl = {0};
        Rectangle_TypedefAssign(&rect, SUBMENU_TITLE_X, SUBMENU_TITLE_Y, CHAR_WIDTH(FONT_WIDTH_32, 4), BUTTON_HEIGHT);
        Rectangle_TypedefAssign(&rect, SM_COLUM2_BUTTON_X, SM_ROW1_BUTTON_Y, CHAR_WIDTH(FONT_WIDTH_32, 5), BUTTON_HEIGHT);
        Rectangle_TypedefAssign(&rect, SM_COLUM2_BUTTON_X, SM_ROW2_BUTTON_Y, CHAR_WIDTH(FONT_WIDTH_32, 5), BUTTON_HEIGHT);
        Rectangle_TypedefAssign(&rect, SM_COLUM2_BUTTON_X, SM_ROW3_BUTTON_Y, CHAR_WIDTH(FONT_WIDTH_32, 6), BUTTON_HEIGHT);
        Control_TypedefAssign(&ctrl, &rect,&ctrl,AppLCM_ComSetHandler,NO, 4, "Com Setting", 0);
        Control_TypedefAssign(&ctrl, &rect,&ctrl,AppLCM_ComSetHandler,1, 5, "1.Process1", 0);
        Control_TypedefAssign(&ctrl, &rect,&ctrl,AppLCM_ComSetHandler,2, 5, "2.Process2", 0);
        Control_TypedefAssign(&ctrl, &rect,NULL,      AppLCM_ComSetHandler,3, 6, "3.Process3", 0);

        AppLCM_UserInterfaceProcess(COUNTOF(rect), TRUE, rect, ctrl);
}


头文件如下:


#ifndef__TSP_H__
#define__TSP_H__

#include "stm32f10x.h"
/* MAX RECEIVE BUFFER */
#define MAX_RECEIVE_BUFFER    50u

typedef enum {Vertical = 0, Horizontal}DisplayDirection;

/* Define some states of button pressed */
typedef enum
{
        FAULT      = -1,
        QUIT       = 0x0011,
        FUNCTION   = 0X0022,
        CYCLE      = 0X0033,
        REDRAW   = 0X0044
}ClickEventState_Typedef;
                                               
typedef structtagTOUCHXY
{
        u16 x;
        u16 y;
}TOUCH_XY;

typedef struct tagRETANGLE_AREA
{
        u8areaNo;
        u16 sx;
        u16 sy;
        u16 ex;
        u16 ey;
}RETANGLE_AREA;

/* the button's retangle */
typedef struct {
    u16 nLeft;
    u16 nTop;
    u16 nWidth;
    u16 nHeight;
}Rectangle_Typedef;

/* The location of button which happened event. */
typedef struct {
    u16x;
    u16y;
}KEY_EVENT_Typedef;       
/* Function point of event */
typedef s32ClickEvent(KEY_EVENT_Typedef *ptEvent, u32 *btnNo);
/* Control block */
typedef struct tagControl Control_Typedef;
struct tagControl
{
      Rectangle_Typedef    *tWindow;         //Button Retangle
      Control_Typedef      *ptNext;            //point to next struct class
      ClickEvent               *fnClickEvent;   //process this button which was being pressed
      u32                        index;                       //the only index for the button on a UI picture
      u8                           charNums;          //numbers of characters of the button's caption
      char                         *btnCaption;      //string of button caption
      u32                        timeOfCycle;      //reserved datas
};



#endif        //end of __TSP_H__



xf331785508 发表于 2016-6-7 17:18:17

Gorgon_Meducer 发表于 2013-12-5 17:52
简单来说这么处理的

屏幕上的按钮和文本框都是一个矩形区域,你可以定义一个数据结构


才补上代码,傻孩子大师看看代码冗余度如何?

Gorgon_Meducer 发表于 2016-7-1 10:32:52

xf331785508 发表于 2016-6-7 17:18
才补上代码,傻孩子大师看看代码冗余度如何?

能实现功能就是第一步,自己用着用着就能感觉出哪里是多余的。
这个代码至少我看起来还是很不错的!

ponder2077 发表于 2016-8-5 19:19:17

好好消化..

KongQuan 发表于 2016-8-5 21:53:57

学习了。

kinsno 发表于 2017-2-9 09:08:40

我是来打酱油的吗?
路过。。


bigwei 发表于 2017-2-9 13:57:07

顶一下,研究研究。

stevenh 发表于 2017-2-9 22:06:25

谢谢分享!

STT 发表于 2017-3-28 11:46:03

好好消化..

chen849928055 发表于 2017-3-31 11:11:51

xf331785508 发表于 2016-6-7 16:50
根据傻孩子的砖,我斗胆晒一下我的糟玉。以飨坛友。




楼主你换页后,如果还有按键,且位置也不一样,你是怎么处理的?

chen849928055 发表于 2017-3-31 11:19:34

Gorgon_Meducer 发表于 2013-12-5 17:52
简单来说这么处理的

屏幕上的按钮和文本框都是一个矩形区域,你可以定义一个数据结构


老师换页了(按键区域不一样了),怎么处理,结构体里面还要加什么元素?

xf331785508 发表于 2017-3-31 13:25:41

chen849928055 发表于 2017-3-31 11:19
老师换页了(按键区域不一样了),怎么处理,结构体里面还要加什么元素?

在这个函数 AppLCM_ComSetSubMenu里面进行按钮坐标初始化。

chen849928055 发表于 2017-4-24 16:59:14

楼主的ASCII码的字符感觉挺圆滑的,你是怎么做到的,普通的字摸软件生成的ASCII码字符好多锯齿

xf331785508 发表于 2017-4-25 09:05:17

chen849928055 发表于 2017-4-24 16:59
楼主的ASCII码的字符感觉挺圆滑的,你是怎么做到的,普通的字摸软件生成的ASCII码字符好多锯齿 ...

字符看起来圆滑不圆滑,根字模软件无关,是单个象素点的尺寸大小决定的。楼主位的图片中LCM自带字模,可有多种大小的字体提供。单象素点越小,同样字号的字体圆滑度越好,但也不是绝对的,假如象素点的尺寸足够小,同样字号的字体,肉眼可能就看不清了。现在大家对surface的显示效果的批判就是这个原因,虽然细腻,但字太小,看着也不舒服。
如下图,同样的字号,借助放大镜,就展示了不同尺寸象素大小的显示效果。

chen849928055 发表于 2017-4-25 09:15:54

xf331785508 发表于 2017-4-25 09:05
字符看起来圆滑不圆滑,根字模软件无关,是单个象素点的尺寸大小决定的。楼主位的图片中LCM自带字模,可 ...

是的,看emwin里有程序对字符显示做了抗锯齿化的处理,你可知道哪有类似emwin源码供参考吗?

chen849928055 发表于 2017-4-27 11:24:04

楼主的菜单结构是裸机的,还是上了系统

xf331785508 发表于 2017-4-27 13:52:23

chen849928055 发表于 2017-4-27 11:24
楼主的菜单结构是裸机的,还是上了系统

裸机的,没上系统。响应要求不高,另外,那时候能力有限,对伪并行状态机或RTOS不是很在行,所以直接上裸机,队列化运行。
页: [1]
查看完整版本: 我的串口屏如何响应UI中的按钮,求个思路?