摘要: 图形用户界面(Graphic User Interface, 简称GUI)的广泛流行是当今计算机技术的重大成就之一, 它极大地方便了非专业用户的使用。本文简要介绍当前国内外几种嵌入式GUI 系统的实现方式与特点。对基于Qt 的嵌入式GUI---Qt/Embedded的交叉开发平台、窗口系统、图形引擎的实现技术以及Qt 的核心特性---信号与槽机制进行了分析。最后给出了Qt/Embedded 应用程序的移植过程, 移植过程采用交叉编译, 系统界面直观简洁, 易于操作。
1 引言
图形用户界面系统(GUI)是系统级的底层软件, 它可以和文件系统、操作系统内核等一起构成一个完整的操作系统。GUI为用户提供了与应用系统交互的可视化通道, 同时GUI 为程序员提供了一种编程模式, 即GUI 负责系统的可视化界面的生成、管理以及系统与用户之间的信息交互, 而程序员只需专注于对实际应用的分析。
嵌入式GUI 除了以上特点, 还要求简单、直观、可靠、占用资源小且反应快速, 以适应嵌入式系统硬件资源有限的条件。
另外, 由于嵌入式硬件本身的特殊性, 嵌入式GUI 应具备高度可移植性和可裁剪性, 以适应不同硬件平台的需求。
2 国内外几种嵌入式GUI 系统实现方式与特点
为了适应日益扩大的嵌入式Linux 市场的需求, 国内外的相关研究机构和开发商已经或者正在开发一大批嵌入式图形系统项目和原型产品。其中较为着名的开放源码项目有Tiny X(小型的X 窗口系统)、Microwindows、MiniGUI、Qt/Embedded 等。
Tiny X:是标准X- windows 在嵌入式系统的小巧实现, 作为一个图形环境, X- window 是成功的, 但由于在体系接口上的原因, 限制了它对游戏、多媒体的支持能力。
Microwindows: 典型的基于Server/Clinent 体系结构的GUI系统, 提供了相对完善的图形功能和一些高级的特性, 如Alpha混合、三维支持等。该系统为了提高运行速度, 也改进了基于Socket 套接字的X 实现模式, 采用了基于消息机制的Server/Client 传输机制。
MiniGUI:由国内自由软件开发人员设计开发, 是一种面向嵌入式系统或者实时系统的图形界面支持系统。MiniGUI 具有资源消耗小、速度快、效率高的特点, 但目前还不是很成熟, 主要表现在:体系结构不完善, 自有图形引擎的功能较弱, 控件的可定制性不好, 基于线程机制的系统脆弱性在复杂应用中更为突出, 尤其是缺少一个方便的图形开发环境。
Qt/Embedded: 缩写为Qt/E, Qt 是Trolltech 公司的产品, 是一个多平台的C++图形用户界面应用程序框架, 它注重于给用户提供精美的图形用户界面所需要的所有元素。而且它是基于一种面向对象的思想, 所以用户对其对象的扩展是相当容易的, 并且他还支持真正的组件编程。这也是本文将要重点介绍的内容。
3 Qt /E 的介绍及开发环境的建立
3.1 Qt/E 体系结构
3.1.1 交叉开发平台
Qt 是用于本地化跨平台应用开发的领先性框架。Qt 所有平台的API 是一致的。这就意味着在一种平台上写的应用程序, 在新的平台上经过重新编译和连接便能运行于该新平台上。因此, 软件开发者通过开发和维护一种平台的应用源码来用于多种平台的开发。同样, 嵌入式Qt 也可以移植基于Qt 的软件到嵌入式Linux 中。Qt 可提供的平台, 如图1:
Qt/Windows: 用于Microsoft Windows xp、2000、NT4、Me/98.
Qt 库使用Windows 的GDI API 来实现, 并且使用微软的窗口系统; Qt/X11:包括Linux、HP- UX、Sun Solaris、Digital UNIX、SGI Irix、IBMAIX 等。Qt 库使用X11 库来实现, 并且使用X 窗口系统; Qt/E:包括一个完整的窗口系统, 并允许设计者轻易地加入各种显示设备和硬件输入设备(如鼠标、键盘、触摸屏等); Qt/Mac:
用于Mac OS X 平台。Qt 对不同平台的专门API 进行了封装, 如文件处理、网络(操作, 协议)、进程处理、线程、数据库访问等。
3.1.2 Qt/E 的窗口系统
Qt/E 的窗口系统采用一种客户/服务器体系结构, 如图2所示。一个典型的嵌入式Qt 窗口系统一般包括一个服务器进程、一个或多个客户进程(简称服务器和客户)。服务器负责为客户和其本身分配显示区域、生成鼠标和键盘事件。而客户则通过与服务器通信来申请显示区域, 接收鼠标和键盘事件。客户可以直接访问所分配的显示区域, 以便为用户提供GUI 服务。服务器和客户通过共享内存的方式来传递所有分配显示区域上的信息。
服务器:服务器维护着一组区域, 当窗口被创建、移动、改变大小和破坏时, 通过这组区域来改变每个客户的申请。该区域存放在共享内存中, 在执行绘图操作时, 客户可以从中读取信息; 客户:嵌入式Qt 为客户提供的API 与标准的Qt API 是一致的。当Qt/E 客户使用Qt API 画线时, Qt/E 库直接访问显存, 完成画线工作。嵌入式Qt 客户库还负责处理所有的绘画操作, 另外, 他还处理那些定制的窗口装饰(如标题条等)。
3.1.3 Qt/E 图形引擎的实现
Qt/E 的底层图形引擎基于帧缓冲(frame buffer)。帧缓冲是标准显示设备驱动接口, 使用MMAP 系统将帧缓存映射到应用程序虚拟内存空间, 这样应用程序可以访问它。
帧缓冲驱动程序的实现分为两个方面, 一方面是LCD 等相关硬件及缓存的初始化, 包括图形在缓冲区的创建和设置DMA 通道; 另外一方面是对画面缓冲区的读写, read、write 及lseek 等系统调用接口可以调用驱动程序的读写函数。至于将画面缓冲区的内容输出到LCD 显示屏上, 则由硬件自动完成。
当设置DMA 通道和画面缓冲区后, DMA 开始正常工作并将缓冲区中的内容不断发送到LCD 上, 这个过程基于DMA 对于LCD 的不断刷新。帧缓冲驱动程序则将数据写入帧缓存中, 这通过映射MMAP 来实现。
在Qt/E 中, QScreen 类为抽象出的底层显示设备基类, 其中声明了对于显示设备的基本描述和操作方式, 如打开、关闭、获得显示能力、创建GFX 操作对象等。另外一个重要的基类是QGFX 类。该类抽象出对于显示设备的具体操作接口(图形设备环境), 如选择画刷、画线、画矩形、alpha 操作等。以上两个基类是Qt/E 图形引擎的底层抽象, 其中许多函数是虚函数。当具体的显示设备(如具体的帧缓冲设备和虚拟帧缓冲设备)从其派生类时, 这些派生类会继承并重载基类中的虚函数来实现。
3.2 Qt 系统的信号与槽(Signal and Slot)机制
信号/槽是一种高级接口, 应用于对象之间的通信, 是Qt 的核心特性, 也是Qt 区别于其他工具包的重要地方。信号/槽是Qt 自行定义的一种通信机制, 独立与标准的C/C++语言, 因此要正确的处理信号和槽, 必须借助于一个称为MOC(Meta ObjectCompiler)的Qt 工具, 该工具是一个C++预处理程序, 它为高层次的事件处理自动生成所需要的附加代码。
Qt 中使用信号/槽机制替代原始回调和消息映射机制。当一个特定事件发生的时候, 一个信号被发射。Qt 的窗口部件有很多预定义的信号, 但是程序员总是可以通过继承来加入自定义的信号。槽就是一个可以被调用处理特定信号的函数。Qt 的窗口部件有很多预定义的槽, 但是通常的习惯是加入程序员自己的槽, 这样就可以处理自己所感兴趣的信号。
所有从QObject 或其子类派生的类都能够包含信号和槽。
当对象改变其状态时, 信号就由该对象发射出去, 这就是对象所要做的全部事情。它不知道另一端是谁在接收这个信号, 这就是真正的信息封装, 它确保对象被当作一个真正的软件组件来使用。槽用于接收信号, 但它们是普通的对象成员函数。
一个槽并不知道是否有任何信号与自己相连接。而且, 对象并不了解具体的通信机制, 这样就可以相对容易地开发出代码可高重用的类。
多个信号可以连接一个槽, 一个信号也可以连接多个槽,甚至一个信号与另外一个信号相连接也是可能的, 这时无论第一个信号什么时候发射系统都将立刻发射第二个信号, 如图3所示。总之, 信号与槽构造了一个强大的部件编程机制。
4 Qt /E 的移植
在PC 上基于Qt/X11 和qvfb 的应用程序调试通过以后就可以将应用程序软件移植到目标平台上, 但前提是要保证framebuffer、触摸屏等驱动程序的正常运行。Qt/E 移植过程如下:
1) 交叉工具链的安装。
本文选用的交叉工具链是arm- linux- gcc 系列。安装包为:
cross- 2.95.3.tar.bz2 将其拷贝到某个目录下, 依次执行如下命令:
tar - jxvf cross- 2.95.3.tar.bz2这个工具链应该安装的路径是:/usr/local/arm/2.95.3(或者可以通过查看GCC 版本号, 可以得到一些信息, 从版本信息中可以看到"- prefix=…… ", 这就是GCC 安装的路径, 它是在GCC编译前通过prefix 选项配置的)。
¥ mkdir - p /usr/local/arm
¥mv ./2.95.3 /usr/local/arm
然后, 在环境变量PATH 中添加路径, 就可以直接使用arm- linux- gcc 命令了。
¥export PATH=/usr/local/arm/2.95.3/bin:$PATH
2) 交叉编译Qt/E 库安装完交叉工具链之后, 需要对Qt/E 软件包进行交叉编译。将Qt/E 的源代码拷贝到另外一个目录下, 依次执行如下命令序列:
tar xfz qt- embedded- free- 3.2.1.tar.gz
cd qt- embedded- free- 3.2.1
export QTDIR=¥PWD
export QTEDIR=¥QTDIR
export PATH=¥QTDIR/bin:¥PATH
export LD_LIBRARY_PATH = ¥QTDIR/lib: ¥LD_LIBRARY_
PATH
export PATH=/usr/local/arm/2.95.3/bin:¥PATH
./configure - embedded arm - thread
Qt/E 的配置选项可以参考。/configure –help.其中比较关键的是- embeddded arm 表示配置为目标板为ARM 的嵌入式用途, 在编译过程中会进行多级优化以减小体积, 提高效率。
3) 交叉编译Qt/E 应用程序。
有了交叉工具链以及经过交叉编译的Qt/E 库之后, 就可以将驱动程序或应用程序进行编译, 然后发布到ARM平台上。
首先, 编写项目工程文件。pro, 然后用qmake 工具生成Makefile 文件, 最后调用Make 指令编译、链接即可。这个过程中, 在生成Makefile 文件之前, 需要修改环境变量使其指向交叉编译后的Qt/E 库所在目录。最终生成ARM平台目标代码,即可在目标平台上运行测试。
5 总结
嵌入式产品的广泛应用带动了图形用户界面(GUI)的迅速发展, 嵌入式系统需要一个高性能、高可靠的GUI 支持。Qt/E 延续了Qt 在桌面系统的所有功能, 丰富的API 接口和基于组件的编程模型使得嵌入式Linux 系统中的应用程序开发更加便捷。由于Qt/E 本身面向高端的手持设备和移动设备, 将成为未来嵌入式系统的主流GUI.
本文创新观点: 本文首先比较当前流行的国内外几种嵌入式GUI 系统的实现方式与特点, 分析它们的优缺点。着重介绍了基于Qt 的嵌入式GUI---Qt/Embedded, 并通过举例来具体说明Qt/Embedded 应用程序的移植过程。