本系统中采用的多媒体播放器是TCPMP,TCPMP播放器播放速度很快且支持多达几十中多媒体格式。TCPMP开源项目,同时支持Windows CE操作系统,而且提供很好的扩展性,例如需要重新编写TCPMP界面只需重新编写interface.plg即可。TCPMP提供全部的源代码,移植非常方便,只需编译后将生成的文件拷贝到目标机器运行即可。TCPMP多媒体播放器界面非常简洁,如图 5.35所示。
图 5.37 TCPMP软件界面
另外、TCPMP还支持应用集成,可以将TCPMP播放的核心移入到指定应用程序的指定界面位置,实现多媒体播放和其他任务同时工作的效果,常用于电梯广告播放器平台上。
本系统的导航软件采用凯立德公司的导航软件,凯立德导航软件经历数10多年的发展,已经发展成为一款成熟的导航软件平台。凯立德公司推出很多嵌入式、手机等平台的导航软件版本,有支持Windows Mobile平台的、Symbian平台的,当然也有Windows CE平台。凯立德导航软件界面如图 57所示。
另外,同行相比,凯立德导航软件提示信息比较全,高速公路上,前方的主要出入口距离有多少,服务区距离多少,全部有提示,而且可以根据前方服务区的距离,计划你可以在哪儿休息,在哪儿加油。
图 5.38 凯立德导航软件
为了提供系统的交互性、可操作性,在本系统集成之际,还需要设计一个可用交互的界面软件,并开机启动该软件,320×240分辨率显示。考虑系统本身功能比较独立,在界面分块的时候,主要提供了GPS导航、Internet、TCPMP、游戏、常用工具和我的设备等几个调用功能,这样界面清爽和简洁,如图 5.39所示;
图 5.39 TQSHELL界面
不仅如此,在我们开发板上还支持KEY键(如图 5.40所示),提供左右上下切换等功能。因此、在TASHELL界面设计的时候,我们同样支持了KEY按键功能。支持KEY按键功能其实很简单,只需响应OnKeyDown事件即可。
图 5.40 KEY按键原理图
整个TQSHELL界面采用的BMP图片绘制的方式进行设计的,其中每个按键的效果展示都是由一张张图片切换产生的效果。图片绘制是TQSHELL界面设计的关键,如下详细介绍图片绘制的代码实现,首先介绍CreateCompatibleDC[7]和BitBlt这两个重要的函数。
(1) CreateCompatibleDC函数
该函数用于创建一个与pDC所指向的设备环境兼容的内存设备环境——也称内存设备上下文。内存设备环境是一块用以显示的内存块,在复制内存图像到实际的显示设备前用来存储图像,这也正是避免闪屏的原因之所在,其函数原型如下;
virtual BOOL CreateCompatibleDC( CDC* pDC );
其中pDC指向一个设备环境,在MFC中常用GetDC()获取。如果pDC为空,函数会创建一个与系统显示兼容的内存设备环境。
调用该函数,当内存设备环境创建后,GDI会自动为它装载一个黑白位图。GDI的输出函数只有当内存设备环境上有了位图画布之后,才能进行输出。但是用该函数时,有一点需要注意,即该函数只能用来为支持光栅操作的设备创建兼容的设备环境。
(2) BitBlt函数
如上所述,CreateCompatibleDC函数用于创建设备上下文兼容的内存设备环境,BitBlt函数则用于从源设备上下文(即内存设备环境)拷贝位图到这个当前设备上下文,该函数原型如下;
BOOL BitBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop );
l x 指定目标矩形左上角的逻辑x坐标。
l y 指定目标矩形左上角的逻辑y坐标。
l nWidth 指定目标矩形和源位图的宽度(逻辑单位)。
l nHeight 指定目标矩形和源位图的高度(逻辑单位)。
l pSrcDC 指向CDC对象的指针,标识待拷贝位图的设备上下文。假如dwRop指定不包括源的光栅操作,则它必须为NULL。
l xSrc 指定源位图左上角的逻辑X坐标。
l ySrc 指定源位图左上角的逻辑Y坐标。
l dwRop 指定要执行的光栅操作。光栅操作代码定义GDC如何合并输出操作中的颜色,包括当前画刷、可能的源位图和目标位图。
使用BitBlt函数,应用可以在字节边界上对齐窗口或客户区域,保证BitBlt操作发生在以字节对齐的矩形上。
在字节对齐矩形上的BitBlt操作比未经字节对齐的矩形上的BitBlt操作快许多。假如想对自己的设备上下文指定字节对齐类风格,必须登记窗口类而不要依靠Microsoft基本类,可使用全局函数AfxRegisterWndClass。
一旦使用目标设备上下文和使用源设备上下文,GDI变形nWidth和nHeight。假如结果延伸不匹配,必要时GDI使用Windows StretchBlt函数压缩或拉伸源位图。假如目标、源和特征位图颜色格式不同,BitBlt转换源和特征位图以匹配目标,转换中使用目标位图的前景和背景色。
BitBlt函数把单色位图转换为彩色时,它设置白色(1)为背景色,黑色(0)作为前景色。使用目标设备上下文的背景和前景色。要把彩色转换为单色,BitBlt把与背景色匹配的像素设置为白色,其余所有像素设置为黑色。在从彩色到单色的转换中,BitBlt使用彩色设备上下文的前景和背景色。
注意,并非所有的设备上下文都支持BitBlt。为检查给定设备上下文是否支持BitBlt,使用GetDeviceCaps成员函数并指定RASTERCAPS索引。
了解这两个函数的作用之后,编写绘图程序就相当简单了,TQSHELL界面中绘图程序如程序清单 5‑55所示;
程序清单 5‑55 绘制图片代码
CDC* pDC = GetDC () ;
CDC memDC ;
memDC.CreateCompatibleDC ( pDC ) ;
CBitmap bmp,bmp1 ;
CBitmap* pOldBitmap ;
bmp1.LoadBitmap ( m_map) ;
pOldBitmap = memDC.SelectObject ( &bmp1 ) ;
pDC->BitBlt ( m_rect[i].TopLeft().x, m_rect[i].TopLeft().y, m_rect[i].Width(),
m_rect[i].Height(), &memDC, 0, 0, SRCCOPY ) ;
memDC.SelectObject ( pOldBitmap ) ;
memDC.DeleteDC () ;
ReleaseDC ( pDC ) ;
在系统中,考虑到如果TQSHELL所有的事件都是硬实现而没有动态效果的话未免有失系统交互性,因此在TQSHELL中,我们采用了双图片切换的方式来模拟按键触发,如图 5.41、图 5.42所示。
图 5.41 按键之前
图 5.42 按键之后
按键模仿需要响应两个事件,一个OnLButtonDown、另一个是OnLButtonUp。当OnLButtonDown事件发生之后,图片切换,当OnLButtonUp事件发生之后,图片恢复,代码如程序清单 5‑56、程序清单 5‑57所示。
程序清单 5‑56 OnLButtonDown事件
bmp.LoadBitmap ( IDB_GPS_W ) ;
CBitmap* pOldBitmap = memDC.SelectObject ( &bmp ) ;
pDC->BitBlt ( m_rect[m_prePick].TopLeft().x, m_rect[m_prePick].TopLeft().y, m_rect[m_prePick].Width(),
m_rect[m_prePick].Height(), &memDC, 0, 0, SRCCOPY ) ;
memDC.SelectObject ( pOldBitmap ) ;
程序清单 5‑57 OnLButtonUp事件
CopyBMP(IDB_GPS_W,0);
硬件平台的设计过程当中,考虑到操作的方便,增加了KEY按键的实现,主要针对上下左右等几个功能。在TQSHELL为很好的利用这样的条件,以增加系统的可交互性,在实现的过程当中,响应KEY按键事件。支持KEY按键其实很简单,只需实现OnKeyDown事件即可,事件的实现的时候,有一点需要注意,KEY按下之后,前一个KEY应当恢复,KEY按键响应函数如程序清单 5‑58所示。
程序清单 5‑58 OnKeyDown事件
void CGPSDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
m_prePick=m_currentPick ;
if ( nChar == VK_UP|| nChar == VK_LEFT )
{
switch (m_prePick)
{
case 0:
//GPS黑别的白
CopyBMP(IDB_GPS_B,0);
CopyBMP(IDB_MP3_W,1);
CopyBMP(IDB_MP4_W,2);
CopyBMP(IDB_PICTURE_W,3);
CopyBMP(IDB_TOOL_W,4);
CopyBMP(IDB_SET_W,5);
m_currentPick = 0 ;
break ;
......
}
}
if ( nChar == VK_DOWN || nChar == VK_RIGHT)
{
switch (m_prePick)
{
case 0:
//MP3黑别的白
CopyBMP(IDB_GPS_W,0);
CopyBMP(IDB_MP3_B,1);
CopyBMP(IDB_MP4_W,2);
CopyBMP(IDB_PICTURE_W,3);
CopyBMP(IDB_TOOL_W,4);
CopyBMP(IDB_SET_W,5);
m_currentPick = 1 ;
break ;
......
default:
break;
}
}
CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
}
TQSHELL界面程序是一个系统集成界面程序,为保证系统能运行,TQSHELL必须实现进程调用,调用子软件运行,实现如GPS导航、多媒体播放等方面的操作。在MFC中,进程调用的函数有很多中,但是在本系统中支持ShellExecuteEx函数,如下介绍ShellExecuteEx函数,介绍ShellExecuteEx之前,我先介绍SHELLEXECUTEINFO结构体[8]。
(1) SHELLEXECUTEINFO结构体
该结构体作为参数辅助ShellExecuteEx函数的调用进程,指定需要调用的进程相关的参数,该结构体原型如程序清单 5‑59所示;
程序清单 5‑59 SHELLEXECUTEINFO 结构体
typedef struct _SHELLEXECUTEINFO {
DWORD cbSize;
ULONG fMask;
HWND hwnd;
LPCTSTR lpVerb;
LPCTSTR lpFile;
LPCTSTR lpParameters;
LPCTSTR lpDirectory;
int nShow;
HINSTANCE hInstApp;
LPVOID lpIDList;
LPCTSTR lpClass;
HKEY hkeyClass;
DWORD dwHotKey;
union {
HANDLE hIcon;
HANDLE hMonitor;
} DUMMYUNIONNAME;
HANDLE hProcess;} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;
在进程调用的过程当中,SHELLEXECUTEINFO结构体中的这些参数是可以选择性的设置,如下一一介绍。
l lpDirectory:可选。指明工作目录的名字,成员没有说明,则默认为当前目录
l nShow:必须。指定打开的程序的显示方式,为SW_值中的一个。
l hInstApp:用于输出,如果设置SEE_MASK_NOCLOSEPROCESS S值并且ShellExecuteEx 调用成功,则该项的值大于32,如果调用失败,则将设置为 SE_ERR_XXX 的错误值。
l lpIDList:一个ITEMIDLIST结构的地址,用来存储成员的特别标识符,当fMask不包括SEE_MASK_IDLIST或SEE_MASK_INVOKEIDLIST时该项被忽略
l lpClass:用以指明文件类别的名字或GUID,当fMask不包括SEE_MASK_CLASSNAME时该项被忽略
l hkeyClass:获得已在系统注册的文件类型的Handle,当fMask不包括SEE_MASK_HOTKEY时该项被忽略
l dwHotKey:程序的热键关联,低位存储虚拟关键码(Key Code),高位存储修改标志位(HOTKEYF_),修改标志为(modifier flags)的详细列表请看WM_SETHOTKEY消息的描述,当fmask不包括SEE_MASK_HOTKEY时该项被忽略
l hIcon :取得对应文件类型的图标的Handle,当fMask不包括SEE_MASK_ICON时该项被忽略
l hMonitor :将文档显示在显示器上的Handle,当fMask不包括SEE_MASK_HMONITOR时该项被忽略
l hProcess:指向新启动的程序的句柄。若fMask不设为SEE_MASK_NOCLOSEPROCESS则该项值为NULL。但若程序没有启动,即使fMask设为SEE_MASK_NOCLOSEPROCESS,该值也仍为NULL。
(2) ShellExecuteEx函数
ShellExecuteEx函数以SHELLEXECUTEINFO结构体为参数,用于调用SHELLEXECUTEINFO结构体中指定的进程,该函数原型如下;
BOOL ShellExecuteEx(LPSHELLEXECUTEINFO lpExecInfo);
了解SHELLEXECUTEINFO结构体和ShellExecuteEx函数之后,TQSHELL中调用ShellExecuteEx函数实现进程调用,代码实现其实很简单,如程序清单 5‑60所示;
程序清单 5‑60 进程调用
tem = L"//Storage Card//KLD//NaviOne.exe";
exeshell.cbSize = sizeof(SHELLEXECUTEINFO);
exeshell.lpFile = tem;
exeshell.hwnd = NULL;
exeshell.nShow = SW_SHOW;
ShellExecuteEx(&exeshell);
DesktopBar=::FindWindow(L"HHTaskBar",NULL);
::ShowWindow(DesktopBar,SW_HIDE);
TQSHELL编译完成之后,获得TQSHELL.EXE和TQSHELL.LIB文件之后,为了方便开机就启动本界面,我们需要将这两个文件加入到内核中,加载到内核中的步骤如下;
(1) 编辑LNK文件
该文件其实就是一个快捷文件,点击可直接运行指定目录下的应用程序。该文件的内容如图 5.43所示;
图 5.43 LNK文件内容
(2) 加载到内核当中
在Windows CE中,需要将应用程序加载到内核当中,只需编辑Pratfrom.bib文件即可,如图 5.44所示;
图 5.44 加载TQSHEEL.exe到内核
(3) Windows CE启动后直接运行TQSHELL.exe程序
Windows CE支持启动直接运行用户程序,设置很简单,因为Windows CE启动后默认是启动explorer.exe程序,如果要替换成指定的应用程序,只需设置相关的注册表即可,如程序清单 5‑60所示;
程序清单 5‑61 启动注册表
[HKEY_LOCAL_MACHINE/init]
"Launch50"="Windows//TQSHELL.EXE"
"Depend50"=hex:14,00,1e,00
Windows CE启动之后,TQSHELL.EXE运行的界面比起原始Windows CE界面要清爽很多,如图 5.45、图 5.46所示;
图 5.45 主界面
图 5.46 常用工具界面