业务系统
1.总结前面#
- 前面实现了各个子系统:显示、输入、文字、UI、页面,它们只是提供基础能力,跟业务逻辑没有关系
- 这样的架构很容易扩展,可以在这上面实现各种业务,比如可以做收银机、自动售卖机、智能称、取号机,如果再加上摄像头显示,就可以做出可视对讲、视频监控、人脸红外测温
- 对于不同的产品,我们只需要写出自己页面函数,即PageAction结构体
2.业务系统流程#
可以写出框架,创建unittest\main.c
:
在page/mainpage.c
写出框架:
3.配置文件处理#
通过配置文件定义各个测试工具的项目。
先在include/config.h
定义结构体、常量与函数声明:
实现上面三个接口函数,以及配置文件解析函数,创建config/config.c
文件:
使用fopen、fgets、sscanf方法,参考《c和指针》 15.7打开流 15.9未格式化的行IO 15.10格式化的行IO
fopen:打开一个特点的文件,并把一个流stream与这个文件关联 原型:
FILE *fopen(const char *pathname, const char *mode);fgets:从指定的stream读取字符串并复制到buffer中,当读取到一个换行符或者数量达到buffer_size-1时停止,且在末尾添加一个
\0
。下一次调用会从这个stream的下一个字符继续开始读取。 原型:char *fgets(char *buffer, int buffer_size, FILE *stream);sscanf:从str中读取字符,并根据format格式代码对字符转进行转换。 原型:
int sscanf(const char *str, const char *format, ...);
4.生成界面#
基本逻辑:
设计每个按钮的高度为宽度的0.618,因此按钮的面积就是width2×0.618
总共的面积要小于屏幕面积:width2×0.618×n<=Xres×Yres
则宽度:width<=Xres×Yres/n/0.618
每行可以显示的按钮数量:n_per_line=Xres/width+1 ,为防止越界,多显示一个
更新计算一下每个按钮的宽度width为Xres/n_per_line
高度height为width×0.618
编写主页面:
mainpage.c
在写出生成按钮界面的函数GenerateButtons
:
- 计算每个按钮的width,height
- 让整体居中,计算每个按钮的Region,保存到全局数组g_atButtons中
- 调用按钮的显示函数,绘制出来
5.处理输入事件#
在主页面的while循环里,获取输入事件,处理输入事件:
读取输入事件:调用input的接口函数
int GetInputEvent(PInputEvent PT_InputEvent);
根据输入找到按钮
GetButtonByInputEvent
: 分为触摸事件和网络事件, 触摸事件:遍历所有按键,判断触摸在哪个按键区域,返回按键 网络事件:获取输入事件字符串,通过名字获取按键并返回。static PButton GetButtonByInputEvent(PInputEvent ptInputEvent){int i;char name[100];if (ptInputEvent->iType == INPUT_TYPE_TOUCH){for (i = 0; i < g_iButtonCnt; i++){if (isTouchPointInRegion(ptInputEvent->iX, ptInputEvent->iY, &g_atButtons[i].tRegion)){/* debug */// printf("touch point is (%d, %d), tRegion sx,sy = (%d, %d) h,w = (%d, %d)\n", ptInputEvent->iX, ptInputEvent->iY,// g_atButtons[i].tRegion.iLeftUpX, g_atButtons[i].tRegion.iLeftUpY,// g_atButtons[i].tRegion.iHight, g_atButtons[i].tRegion.iWidth);return &g_atButtons[i];}}}else if (ptInputEvent->iType == INPUT_TYPE_NET){sscanf(ptInputEvent->str, "%s", name);return GetButtonByName(name);}return NULL;}isTouchPointInRegion
:static int isTouchPointInRegion(int iX, int iY, PRegion ptRegion){if (iX < ptRegion->iLeftUpX || iX >= (ptRegion->iLeftUpX + ptRegion->iWidth)){return 0;}if (iY < ptRegion->iLeftUpY || iY >= (ptRegion->iLeftUpY + ptRegion->iHight)){return 0;}return 1;}GetButtonByName
:static PButton GetButtonByName(char *name){int i;for (i = 0; i < g_iButtonCnt; i++){if (strcmp(name, g_atButtons[i].name) == 0)return &g_atButtons[i];}return NULL;}
调用按钮的OnPressed函数: 我们需要提供自己的按下函数
MainPageOnPressed
,先要在生成按钮界面的函数GenerateButtons
中传入InitButton
:static void GenerateButtons(void){.../* 算出单个按钮的width,height */.../* 居中:计算每个按钮的region */...for (row = 0; (row < rows) && (i < n); row++) //计算region{cur_start_y = start_y + row * height;// pre_start_x = start_x - width;for (col = 0; (col < n_per_line) && (i < n); col++){.../* InitButton */InitButton(GetItemCfgByIndex(i)->name, pButton, NULL, NULL, MainPageOnPressed);i++;}}/* 显示:OnDraw */...}然后在
MainPageOnPressed
中修改按键状态:对于触摸屏事件
1.1 分辨能否被点击
1.2 修改颜色
对于网络事件
2.1 根据传入字符串修改颜色
其余事件无法处理
绘制底色,居中写文字,flush to lcd or web
static int MainPageOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent){unsigned int dwColor = BUTTON_DEFAULT_COLOR;char name[100];char status[100];char *strButton = ptButton->name;/* 1. 对于触摸屏事件 */if (ptInputEvent->iType == INPUT_TYPE_TOUCH && ptInputEvent->iPressure == 0) // 松开的时候响应{/* 1.1 分辨能否被点击 */if (0 == GetItemCfgByName(ptButton->name)->bCanBeTouched){return -1;}/* 1.2 修改颜色 */ptButton->status = !ptButton->status;if (1 == ptButton->status){dwColor = BUTTON_PRESSED_COLOR;}}/* 2. 对于网络事件 */else if (ptInputEvent->iType == INPUT_TYPE_NET){/* 2.1 根据传入字符串修改颜色 */sscanf(ptInputEvent->str, "%s %s", name, status);if (strcmp(status, "ok") == 0){dwColor = BUTTON_PRESSED_COLOR;}else if (strcmp(status, "err") == 0){dwColor = BUTTON_DEFAULT_COLOR;}else if (status[0] >= '0' && status[0] <= '9'){dwColor = BUTTON_PERCENT_COLOR;strButton = status;}else{return -1;}}else{return -1; //其余输入事件无法处理}//绘制底色DrawRegion(&ptButton->tRegion, dwColor);//居中写文字DrawTextInRegionCentrl(strButton, &ptButton->tRegion, BUTTON_TEXT_COLOR);// flush to lcd or webFlushDispalyRegion(&ptButton->tRegion, ptDispBuff);return 0;}
6.综合测试#
修改makefile,添加各个子目录的makefile,
修改顶层目录makfile
链接错误:
这个错误是链接器(ld)在链接过程中发生的问题,提示缺少对 sqrt
函数的引用。这通常是由于数学库(libm)未正确链接导致的。
在顶层目录Makefile中添加-lm,-lm
是指示链接器链接 libm.so,这是数学库的动态链接版本。
计算居中位置出错:
我的方法是x,y都是通过行列计算当前的位置,而韦东山老师的方法y的坐标是通过行计算当前坐标,x的坐标是通过更新的方式。
注意strcmp,两个字符串相等返回0:
测试:
请点击左侧菜单(移动端为右下角)选择要查看的所有笔记吧。