车载系统之 Windows CE 应用软件框架设计
由于 Windows CE 系统的标准界面无法满足车载及其它产品的需求,一般使用 Windows CE 的产品都会采用自定义、个性化的 UI。UI 的实现方案也是千差万别,美观是最基本的要求。其它如扩展性、稳定性等等要求,在设计时也是必须要考虑的。
整个框架暂且不说,先简单说说 UI 最终的实现方法。使用 GDI 贴图可能是大家最容易想到,是的,这确实是最通用的。其对系统的要求也比较低,不必考虑硬有件是否支持;其次,为了实现一些特殊的效果,在产品方案支持的情况下使用 overlay 结合贴图,利用 overlay 的特性完成 UI 之间的快速切换。例如:使用以下 CPU 的方案Telechips、SiRF Prima、iMX,MStar785等使用 Overlay 是没有问题的;但 SiRF A5、MStar 2521等低端的 CPU 则不支持。这两种方案,基本上都是使用 Windows CE 系统提供的功能。接下来是,使用诸如 Open GL ES 做出的支持较好的动画效果的 UI。最后,使用 Windows CE 新特性的 Silverlight 来实现的 UI 产品,现在也慢慢的出现在车载系统中。但使用 Silverlight 对系统的硬件配置要求比较高,现在也只出现在一些高端的产品中。
接下来说说框架,在 Windows CE 下编程,怎么也逃脱不了 Windows 消息框架,至于是使用 MFC 还是使用 Win32 编程,那可以说是仁者见仁智者见智。但无论选用哪一种,它也只是一个基础。UI 框架如何设计,功能如何与 UI 完美的结合,以达到修改 UI 时尽可能不去关心功能代码?这也是 Silverlight 推出时的设计想法:UI 设计和实现,与功能的实现分开。这种分开,个人认为简单的说就是耦合度降到最低,不可能彻底分开的。UI 与功能之间一般通过消息、回调或定时等机制结合在一起。例如有一种使用定时刷新的 UI 方案,界面刷新的工作由一个独立的线程控制,定时检查各 UI 控件是否需要刷新、及如何刷新?功能模块在功能实现时,只需要触发控件的刷新标志即可。
例如如下刷新线程与功能代码:
1 // 刷新线程代码: 刷新各类型控件 2 while 3 { 4 // 字符串显示控件 5 foreach(各个字符串控件) 6 { 7 if(控件.bRefreshFlag) // 如果控件的刷新标志 8 { 9 控件.bRefreshFlag = FALSE; 10 // 刷新操作 11 } 12 } 13 // 按键控件 14 foreach(各个按键控件) 15 { 16 if(控件.bRefreshFlag) // 如果控件的刷新标志 17 { 18 控件.bRefreshFlag = FALSE; 19 // 刷新操作 20 } 21 } 22 // ...... // 其它类型控件 23 Sleep(50); 24 } 25 26 // 功能代码 27 // 功能: 字符串显示控件功能代码 28 // 参数说明: csStr 控件显示的字符串; bRefreshFlag 刷新控件标志 29 void StrSettingFunction(CString &csStr,BOOL &bRefreshFlag) 30 { 31 // 根据功能代码赋值新的字符串 32 CString csNewStr; 33 if(条件1) 34 csNewStr= L"XXX"; 35 else 36 csNewStr = L"YYY"; 37 if(csStr != csNewStr) 38 { 39 csStr = csNewStr; 40 bRefreshFlag = TRUE; // 赋值刷新标志 41 } 42 } 43 // 功能: 按键控件功能功能代码 44 // 参数说明: bEnable 按键使能标志(对应显示Enable/Disable图片); bSelect 按键按下或选中图片; bRefreshFlag 刷新标志 45 void BtnSettingFunction(BOOL &bEnable,BOOL &bSelect,BOOL &bRefreshFlag,...) 46 { 47 BOOL bNewEnable; 48 BOOL bNewSelect; 49 if(条件1) 50 bNewEnable = TRUE; 51 else 52 bNewEnable = FALSE; 53 if(条件2) 54 bNewSelect = TRUE; 55 else 56 bNewSelect = FALSE; 57 if(bEnable != bNewEnable) 58 { 59 bEnable = bNewEnable; 60 bRefreshFlag = TRUE; // 赋值刷新标志 61 } 62 if(bSelect != bNewSelect) 63 { 64 bSelect = bNewSelect; 65 bRefreshFlag = TRUE; // 赋值刷新标志 66 } 67 }
以上功能函数只是一个示例,例如:按键控件可能需要显示字符串,其必然包含一个与字符串显示类似的函数。各个控件都会有显示/隐藏属性,这个在功能代码中也需要体现出现。为了方便控件布局,一般都会支持子窗口,这是一个多个功能的集合。
如何使 UI 的设计具有简单、方便的移植性?这是大家在设计时都会考虑的内容。只所以这样考虑,是想在功能不变、或简单变化的情况下,能快速完成修改、且保证产品的稳定性。特别是一些车载方案公司,对于一些要求不高的小客户在快速确定 UI 后几天就可以完成产品的交付。这种修改,一般包括换图和图片位置的调整。如何简单有限的记录图片与图片的位置等信息呢?早在几年前,就有通过简单的格式化文本来完成的方案。后来标记语言兴起,在嵌入式方案中也得到广泛应用,特别是 XML 语言。XML 语言的特点这里就不多说了,有兴趣的童鞋在网络上查找一下,就能得到答案。在这些方案中,都有用到图片处理的技术,以实现透明、半透明等效果。图片一般采用 BMP 和 PNG 格式,为了方案的保密性等其它一些考虑,图片一般通过工具打包,甚至于,XML 文件也一起打包。这样在不了解打包后文件格式的情况下,客户就必须依赖于软件设计者。
以上三部分结合在一起,就构成了车载应用系统中单个应用软件的框架:控件/子窗体/完整的界面。再给合一个对多个应用控制的逻辑,完成应用启动/关闭(显示/隐藏)等的控制,以完成一个完整的系统的设计实现。