数码相框实现一、显示主界面

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

对于显示主界面,本文目标如下图:

主界面图片

实现显示主界面分三步走
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");
    /* 1. 显示主页面 */
    ShowMainPage(g_atMainPageLayout);
    
    /* 2. 获得输入事件(暂且只有触摸屏作为输入) */
    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;
    
    /* 1.获得一个空闲缓冲块 */
    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;
     	}
        /* 2.在缓冲块中绘制主界面3个图标*/
        while(atLayout->pcIconName)
        {
            atLayout->iLeftTopX = iIconX;
            atLayout->iLeftTopY = iIconY;
            atLayout->iRightBottomX = iIconX + iIconWidth - 1;
            atLayout->iRightBottomY = iIconY + iIconHeight - 1;
            /* 获得Icon位图数据 */
            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;
        /* 3.将缓冲块数据刷到LCD的显存FB */
        /* 注意:如果缓冲块是使用设备本身的LCD显存,不需flush */
    }
    /* 3. 缓冲块数据刷到LCD的显存FB */
    FlushVideoMemToDev(ptVideoMem);
    /* 4. 释放缓冲块,仅仅标记为VM_FREE,方便返回时不用重绘*/
    PutVideoMem(ptVideoMem);
}

/* 获得触摸屏输入事件 */
static int GetMainPageInputEvent(PT_Layout ptLayout, PT_InputEvent ptInputEvent)
{
    T_InputEvent tInputEvent;
    int iRet;
    int i = 0;
    iRet = GetInputEvent(&tInputEvent);  // 调用底层的函数,在input_manager.c 中
    					 // 默认休眠,触摸屏点击时,子线程会唤醒
    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; 也不要高兴的太早,看下图

主界面的一个bug

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

修改之后,OK了!主界面如下

主界面效果图

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

点击主界面某一个图标按钮效果图

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值