在21IC中看到有人在探讨关于触摸屏上菜单实现的问题,附件是我在一个项目中的部分代码,里面有我自己设计的实现规则菜单的算法,所谓规则菜单就是批菜单的条目呈均匀的行列摆放,且每个条目在高度和宽度一样,这样可以极大的简化算法。我的处理方法是,对每个菜单定义一组结构,
/*********************************************************
菜单按钮组结构体
*********************************************************/
typedef struct
{
u8 row;//行数
u8 col;//列数
u8 y;//左上角y座标
u16 x;//左上角x座标
u8 h;//高度
u16 w;//宽度
u8 dy;//y方向间隔
u16 dx;//x方向间隔
u8 titlelen;//按钮内容长度
u16 tx;//按钮内容x方向偏移量
u8 ty;//按钮内容y方向偏移量
u8 cfont;//按钮内容字形
u8 cstyle;//按钮内容粗体及反显
const u8 * title;//按钮内容字符串
}manu_buttonsTypeDef;
/******************************************************************
菜单框架结构体
*******************************************************************/
typedef struct
{
u8 y0;//左上角y座标
u16 x0;//左上角x座标
u8 h;//高度
u16 w;//宽度
u8 thick;//两外框间距离
u8 ty;//按钮内容y方向偏移量
u16 tx;//按钮内容x方向偏移量
u8 cfont;//按钮内容字形
u8 cstyle;//按钮内容粗体及反显
const u8 * title;//按钮内容字符串
}manu_frameTypeDef;
/**************************************************************
菜单结构体
**************************************************************/
typedef struct
{
manu_frameTypeDef frame;
manu_buttonsTypeDef buttons;
}manuTypeDef;
在实际使用一个菜单时需根据菜单排布情况给出结构体中的各值,如下图
所示画面的菜单完整定义为
const u8 testmanu0_title[] =
"测试系统主菜单";
const u8 testmanu0_buttontitle[] =
"复 位 周 期32 分 周 期A 路 模 拟启 动 电 机B 路 模 拟停 止 电 机两 路 模 拟同 步 两 路";
const manuTypeDef testmanu0 =
{
{
5, //u8 y0;//左上角y座标
5, //u16 x0;//左上角x座标
229, //u8 h;//高度
309, //u16 w;//宽度
3, //u8 thick;//两外框间距离
13, // ty;//标题y方向偏移量
43, //u16 tx;//标题x方向偏移量
CFNT_2, //char_fontTypeDef font;//按钮内容字形
CFNT_BOLDREVERSE,//char_styleTypeDef style;//按钮内容粗体及反显
testmanu0_title//const u8 * string;//按钮内容字符串
},
{
4, //u8 row;//行数
2, //u8 col;//列数
62, //u8 y;//左上角y座标
34, //u16 x;//左上角x座标
35, //u8 h;//高度
99, //u16 w;//宽度
44, //u8 dy;//y方向间隔
152, //u16 dx;//x方向间隔
11, //u8 titlelen;//按钮内容长度
6, //u16 tx;//按钮内容x方向偏移量
2, //u8 ty;//按钮内容y方向偏移量
CFNT_12, //char_fontTypeDef font;//按钮内容字形
CFNT_NORMAL,//char_styleTypeDef style;//按钮内容粗体及反显
testmanu0_buttontitle//const u8 * string;//按钮内容字符串
}
};
显示菜单时调用下面函数即可
/********************************************************
显示一屏菜单
********************************************************/
void display_manu(const manuTypeDef* pmd)
{
u8 row, col, x, y, k;
const u8 * pti;
lcm_set_access_2layers();
set_active_window(0,0,40,240);
lcm_clr();
lcm_set_access_layer1();
set_text_mode();
//显示主标题
lcm_set_style(pmd->frame.cstyle);
lcm_set_font(pmd->frame.cfont);
display_string((pmd->frame.x0 + pmd->frame.tx) / 8, pmd->frame.y0 + pmd->frame.ty, (u8 *)pmd->frame.title == 0 ? multiple_manu_title : (u8 *)pmd->frame.title, 0x20);
//显示按钮内容
lcm_set_style(pmd->buttons.cstyle);
lcm_set_font(pmd->buttons.cfont);
pti = (pmd->buttons.title == 0 ? multiple_manu_buttontitle : pmd->buttons.title);
for(row = 0, y = pmd->buttons.y + pmd->buttons.ty; row < pmd->buttons.row; row++, y += pmd->buttons.dy)
{
for(col = 0, x = pmd->buttons.x + pmd->buttons.tx; col < pmd->buttons.col; col++, x += pmd->buttons.dx)
{
set_position(x / 8, y);
for(k = 0; k < pmd->buttons.titlelen; k++)
{
lcm_data_write(*pti++);
}
}
}
set_graph_mode();
//显示外框
rectangle(pmd->frame.x0 - pmd->frame.thick, pmd->frame.y0 - pmd->frame.thick, pmd->frame.x0 + pmd->frame.w + pmd->frame.thick, pmd->frame.y0 + pmd->frame.h + pmd->frame.thick, 1, 0);
rectangle(pmd->frame.x0, pmd->frame.y0, pmd->frame.x0 + pmd->frame.w, pmd->frame.y0 + pmd->frame.h, 1, 0);
//显示按钮
for(row = 0, y = pmd->buttons.y; row < pmd->buttons.row; row++, y += pmd->buttons.dy)
{
for(col = 0, x = pmd->buttons.x; col < pmd->buttons.col; col++, x += pmd->buttons.dx)
{
rectangle(x, y, x + pmd->buttons.w, y + pmd->buttons.h, 1, 0);
}
}
}
比如要显示上面图片中的菜单,则简单地调用即可,如下
display_manu(testmanu0);
显示出菜单之后,要确定触摸了哪个菜单条目,这也很简单,只要调用下面的函数即可
/***********************************************************
分析触摸到的按钮
pmfd 指向标识按钮组的数据
返回触摸到的按键,按从左到右从高到低排列,左上角键值为1
***********************************************************/
uint8_t analyze_touch(const manu_buttonsTypeDef * pmfd)
{
//取得行数和列数
u8 i,j;
u16 x;
u8 y;
//行扫描
for(i = 0, y = pmfd->y; i < pmfd->row; i++, y += pmfd->dy)
{
if((touch_y >= y) && (touch_y <= (y + pmfd->h)))
{
break;
}
}
if(i >= pmfd->row)
{
return 0;
}
for(j = 0, x = pmfd->x; j < pmfd->col; j++, x += pmfd->dx)
{
if((touch_x >= x) && (touch_x <= (x + pmfd->w)))
{
return (i * pmfd->col + j + 1);
}
}
return 0;
}
在这个函数中的touch_x及touch_y是公共变量,分别是触摸点的座标,要注意的是座标值要与显示点位置一一对应。
分析上图菜单的程序大体是这样的
display_manu(&testmanu0);//显示画面
/***********************************************************
在这里启动触摸屏扫描程序
***********************************************************/
while(1)
{
cmd = 0;
if(0x00 != get_touch())//检测是否有触摸
{
//有触摸,取得触摸的菜单条目
cmd = analyze_touch(&testmanu00.buttons);
}
swtich(cmd)
{
case 0:
//没有触摸到菜单条目
break;
case 1:
//复位周期
break;
case 2:
//32分周期
break;
...
...
...
case 8:
//同步两路
break;
default:
break;
}
}
附件中包含完整项目代码及相关部分的原理图。
由于实际项目中对菜单处理要求会复杂一些,所以相关代码不一定与上面给出的代码相同。
本文所用的LCM是TOPWAY公司的LM2029R,其控制器是RA8803, 触摸屏使用STM32的ADC进行控制。
如果仔细看一下代码,你可能还会有其它的收获。
未经本人同意,请勿转载本文。
https://static.assets-stash.eet-china.com/album/old-resources/2008/10/18/bb3a580d-5082-48f1-8393-9723be1f3f6f.rar
用户1713248 2009-7-26 13:29
用户166140 2009-3-13 11:08
用户1354403 2008-12-26 17:19
用户161838 2008-12-18 10:49
用户168318 2008-10-19 19:37
用户168318 2008-10-19 19:37