一、理清思路, 比啥都重要
因为数码相框是在电子书的基础上实现的,因此会继续继承电子书的框架。
即显示主界面和其它界面合为一个子模块,也需向上注册该模块。
对于显示主界面,本文目标如下图:

实现显示主界面分三步走
1)按电子书子模块实现的老套路,搭建子模块的框架
2)显示主界面的逻辑
3)获得触摸屏输入事件的逻辑
1)主界面显示的子模块框架图,如下

这部分代码最好写了,只是添加一个子模块。套路跟之前编写电子书子模块一样。
因此,这里不再赘述,重点在下面的如何显示主界面
2)显示主界面逻辑图,如下

备注:上面的LCD的显存FB位置有误,应放在链表最后面,因为是头插法,第一个插入的会放在最后面。
我觉得,在显示主界面这一块,有两个思想值得学习:
a)缓冲思想
为加速显示界面和图片等,事先分配一些缓冲块用于缓冲界面数据,以获得良好的用户体验。
此外,考虑到内存紧张的板子,第一块缓冲块指向LCD本身的显存。增加了框架的兼容性。
b)封装思想
为确定图标在LCD的显示位置,用layout结构体封装每个图标的名字、坐标。方便界面布局和界面绘制。
抽象共性的能力,是在代码编写中习得的。还是那句话“程序员光说不练假把式”,共勉!
3)获得触摸屏输入事件逻辑

主界面获得触摸屏输入事件逻辑解析:
1)定义一个全局变量:g_atMainPageLayout[] 存储主界面按钮图标的位置和名字
2)调用底层的触摸屏输入事件函数 获得 输入事件(注意:而不是在上层,这样可以降低框架的耦合度,方便代码移植)
(插讲:为啥要降低框架的耦合度?因为层与层之间用抽象接口连接,方便隐藏下层,对上层提供接口,这样分层
不会破坏下层代码。另一方吧,方便代码移植,而不是乱七八糟的调用关系。)
另外,忽略了一点,输入事件也要封装在一个结构体,里面存有类型(触摸屏/按键)、触摸屏压力值、xy坐标值
按键的键值等
3)接着处理输入事情,这里采用while循环,依次判断触点落在主界面的哪个按钮图标上(前面绘制按钮图标时已确定了
每个按钮图标的位置,因此,这里做个范围判断即可确定按下哪个按钮),并返回 索引值(前面全局数组)
4)最后,判断事件类型,做出响应即可。这里只是测试,只是显示出下沉效果
5)处理完后,返回第2)步,循环处理
OK,明确上面三点后,按着顺序依次实现,看下面源码。
二、源码实现, 细节见功夫
对于源码部分,我并不会贴出全部代码,而是根据前面三步分析,依次贴出。
完整代码还请挪步到我的“代码集合”那篇博文获取。
static void MainPageRun(void)
{
int iIndex;
int bPressed = 0;
int iIndexPressed = -1;
T_InputEvent tInputEvent;
printf("before enter ShowMainPage~\n");
ShowMainPage(g_atMainPageLayout);
while(1)
{
iIndex = GetMainPageInputEvent(g_atMainPageLayout, &tInputEvent);
if(tInputEvent.iPressure == 0)
{
if(bPressed)
{
ReleaseButton(&g_atMainPageLayout[iIndexPressed]);
bPressed = 0;
iIndexPressed = -1;
}
}
else
{
if(iIndex != -1)
{
if(!bPressed)
{
bPressed = 1;
iIndexPressed = iIndex;
PressButton(&g_atMainPageLayout[iIndexPressed]);
}
}
}
}
}
static void ShowMainPage(PT_Layout atLayout)
{
int iIconWidth;
int iIconHeight;
int iIconX;
int iIconY;
int iXres, iYres, iBpp;
int iError;
PT_VideoMem ptVideoMem;
T_PixelDatas tOriginIconPixelDatas;
T_PixelDatas tScaledIconPixelDatas;
ptVideoMem = GetVideoMem(ID("main"), 1);
if(NULL == ptVideoMem)
{
DBG_PRINTF("GetVideoMem fail!\n");
return ;
}
if(ptVideoMem->ePicState != PS_GENERATED)
{
if(-1 == GetLCDParams(&iXres, &iYres, &iBpp))
{
DBG_PRINTF("GetLCDParams Fail!\n");
return;
}
iIconHeight = iYres * 2 / 10;
iIconWidth = 2 * iIconHeight;
iIconX = (iXres - iIconWidth) / 2;
iIconY = iYres / 10;
tScaledIconPixelDatas.iBpp = iBpp;
tScaledIconPixelDatas.iWidth = iIconWidth;
tScaledIconPixelDatas.iHeight = iIconHeight;
tScaledIconPixelDatas.iLineBytes = iIconWidth * iBpp / 8;
tScaledIconPixelDatas.iTotalBytes = tScaledIconPixelDatas.iLineBytes * iIconHeight;
tScaledIconPixelDatas.aucPixelDatas = malloc(tScaledIconPixelDatas.iTotalBytes);
if (tScaledIconPixelDatas.aucPixelDatas == NULL)
{
free(tScaledIconPixelDatas.aucPixelDatas);
return;
}
while(atLayout->pcIconName)
{
atLayout->iLeftTopX = iIconX;
atLayout->iLeftTopY = iIconY;
atLayout->iRightBottomX = iIconX + iIconWidth - 1;
atLayout->iRightBottomY = iIconY + iIconHeight - 1;
iError = GetPixelDatasForIcon(atLayout->pcIconName, &tOriginIconPixelDatas);
if(iError)
{
DBG_PRINTF("GetPixelDatasForIcon error!\n");
return;
}
PicZoom(&tOriginIconPixelDatas, &tScaledIconPixelDatas);
PicMerge(iIconX, iIconY, &tScaledIconPixelDatas, &ptVideoMem->tPixelDatas);
FreePixelDatasForIcon(&tOriginIconPixelDatas);
atLayout++;
iIconY += iYres * 3 / 10;
}
free(tScaledIconPixelDatas.aucPixelDatas);
ptVideoMem->ePicState = PS_GENERATED;
}
FlushVideoMemToDev(ptVideoMem);
PutVideoMem(ptVideoMem);
}
static int GetMainPageInputEvent(PT_Layout ptLayout, PT_InputEvent ptInputEvent)
{
T_InputEvent tInputEvent;
int iRet;
int i = 0;
iRet = GetInputEvent(&tInputEvent);
if(iRet)
{
return -1;
}
if(tInputEvent.type != INPUT_EVENT_TYPE_TOUCHSCREEN)
{
return -1;
}
*ptInputEvent = tInputEvent;
while(ptLayout[i].pcIconName)
{
if ((tInputEvent.x >= ptLayout[i].iLeftTopX) && (tInputEvent.x <= ptLayout[i].iRightBottomX) && \
(tInputEvent.y >= ptLayout[i].iLeftTopY) && (tInputEvent.y <= ptLayout[i].iRightBottomY))
{
return i;
}
else
{
i++;
}
}
return -1;
}
三、编译调试, 逃不了的罪
3.1)我的调试是这样的:
1)先解决所有的eroor,忽略的 warning
2)在顶层Makefile 的CFLAGS 加上 Werror, 将所有 warning 视为 error
3)然后按序解决所有的warning,最终 0 errors; 0 warnings
我调试了一个多小时,不可能贴出一个个简单的错误。
不过,最后我会我全部源码 发布在我的“代码集合”
3.2)编译:make
3.3)测试
0. nfs 30000000 192.168.1.103:/work/nfs_root/uImage_nolcdts
1. bootm 30000000
备注:我编译了一个没有lcd 和 ts 的 uImage ,然后烧写到开发板
内核与开发板的内核版本都是 2.6.22.6
2. insmod s3c_ts.ko
3. insmod lcd.ko
4.
export TSLIB_TSDEVICE=/dev/event0
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
5.
在开发板上:mkdir -p /etc/digitpic/icons
把图标文件放到开发板的/etc/digitpic/icons
3.4)测试效果。
即使0 errors ; 0 warning; 也不要高兴的太早,看下图

为啥点击有反映,但却没显示出图标按钮呢?
印证了那句话“三分代码,7分调试”。调试了一个多小时才找到了!(怪我是小白 :)
最终问题出在 分配缓冲块时,没有初始化 ptNew->tPixelDatas.iTotalBytes = VMSize;
导致在 最后并没有 刷到 LCD的显存 FB,因此肯定不会显示。
修改之后,OK了!主界面如下

点击某一个图标按钮时,显示效果如下
