我的串口屏如何响应UI中的按钮,求个思路?
如图,做的串口屏,做了UI按钮,却一直没有想到好的响应方式,代码很傻瓜的去读坐标,比坐标,再判断按键,再更新显示框,不知道有没有好的按钮响应处理思想,没太接触过操作系统,看了看WINDOWS 的消息机制,但好像套用起来一是思维还不太习惯,二是代码量好像很大,还要很好的结构体封装,好的架构才能实现。-------------------------分割线-------------------------------
图片手机拍的,不太好看。
有好的思想的,交流下。 沉得好快。呵呵,一看大部分资讯信息啊。自己再顶一下吧。 本帖最后由 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;
}
楼上高端大气上档次啊 Gorgon_Meducer 发表于 2013-12-5 17:52
简单来说这么处理的
屏幕上的按钮和文本框都是一个矩形区域,你可以定义一个数据结构
够详细。。新书出了没 霸气,好好看看, 霸气~~~~~~~~~~~~~~ 学习大神的方法!!! MINI2440 发表于 2013-12-5 18:36
够详细。。新书出了没
还没…以我这种王婆卖瓜的个性,出了还不满世界的吹~ 我是来听课的。 {:victory:}{:victory:}{:victory:} Gorgon_Meducer 发表于 2013-12-5 17:52
简单来说这么处理的
屏幕上的按钮和文本框都是一个矩形区域,你可以定义一个数据结构
{:victory:} 看一下 默默收藏 强悍,收藏一下。 本帖最后由 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__
Gorgon_Meducer 发表于 2013-12-5 17:52
简单来说这么处理的
屏幕上的按钮和文本框都是一个矩形区域,你可以定义一个数据结构
才补上代码,傻孩子大师看看代码冗余度如何? xf331785508 发表于 2016-6-7 17:18
才补上代码,傻孩子大师看看代码冗余度如何?
能实现功能就是第一步,自己用着用着就能感觉出哪里是多余的。
这个代码至少我看起来还是很不错的! 好好消化.. 学习了。 我是来打酱油的吗?
路过。。
顶一下,研究研究。 谢谢分享! 好好消化.. xf331785508 发表于 2016-6-7 16:50
根据傻孩子的砖,我斗胆晒一下我的糟玉。以飨坛友。
楼主你换页后,如果还有按键,且位置也不一样,你是怎么处理的? Gorgon_Meducer 发表于 2013-12-5 17:52
简单来说这么处理的
屏幕上的按钮和文本框都是一个矩形区域,你可以定义一个数据结构
老师换页了(按键区域不一样了),怎么处理,结构体里面还要加什么元素? chen849928055 发表于 2017-3-31 11:19
老师换页了(按键区域不一样了),怎么处理,结构体里面还要加什么元素?
在这个函数 AppLCM_ComSetSubMenu里面进行按钮坐标初始化。 楼主的ASCII码的字符感觉挺圆滑的,你是怎么做到的,普通的字摸软件生成的ASCII码字符好多锯齿 chen849928055 发表于 2017-4-24 16:59
楼主的ASCII码的字符感觉挺圆滑的,你是怎么做到的,普通的字摸软件生成的ASCII码字符好多锯齿 ...
字符看起来圆滑不圆滑,根字模软件无关,是单个象素点的尺寸大小决定的。楼主位的图片中LCM自带字模,可有多种大小的字体提供。单象素点越小,同样字号的字体圆滑度越好,但也不是绝对的,假如象素点的尺寸足够小,同样字号的字体,肉眼可能就看不清了。现在大家对surface的显示效果的批判就是这个原因,虽然细腻,但字太小,看着也不舒服。
如下图,同样的字号,借助放大镜,就展示了不同尺寸象素大小的显示效果。 xf331785508 发表于 2017-4-25 09:05
字符看起来圆滑不圆滑,根字模软件无关,是单个象素点的尺寸大小决定的。楼主位的图片中LCM自带字模,可 ...
是的,看emwin里有程序对字符显示做了抗锯齿化的处理,你可知道哪有类似emwin源码供参考吗? 楼主的菜单结构是裸机的,还是上了系统 chen849928055 发表于 2017-4-27 11:24
楼主的菜单结构是裸机的,还是上了系统
裸机的,没上系统。响应要求不高,另外,那时候能力有限,对伪并行状态机或RTOS不是很在行,所以直接上裸机,队列化运行。
页:
[1]