1 嵌入式GUI概况 普通Linux有自己标准的GUI系统——X Windows,但是由于X Windows过于庞大和臃肿,极耗系统资源,而且其中不少功能对于嵌入式系统来说是多余的,不适于资源有限的嵌入式系统使用。嵌入式系统与传统计算机系统相比更专门化,其软硬件设计直接从具体应用出发,嵌入式Linux是应用于嵌入式设备开发上的一种操作系统。通常嵌入式设备中的GUI系统占据资源较多,因此对GUI的筛选显得很重要。嵌入式Linux需要高性能、轻量级的GUI系统,于是一批基于嵌入式的Linux的GUI系统应运而生,目前发展比较成熟的主要包括以下几种: - MiniGUI是由魏永明主持开发的轻量级的图形用户支持系统,实现了简化的类Windows 98风格。它基于SVGALib库的多窗口图形用户界面支持的系统,支持Pthread的微客户/服务器结构。它运行在多线程模式下,许多模块都可以单独的线程来运行,同时还可以利用线程来支持多窗口。由于支持力量比较薄弱,相对而言,MiniGUI的维护和再开发成本不可预计。
- Mierowindows/NanoX 是由美国Century Software公司开发的开放源码的嵌入式GUI项目,主要特色在于提供了类似X的客户/服务器体系结构,并提供了相对完善的图形功能。它以较小的资源消耗、通用的framebuffer技术、灵活的分层设计模式和丰富的AP1支持等特点获得了广泛的关注,国内一些人士也参与开发,并编写了GB2312等字符集的支持。但它的图形引擎存在一些问题:无任何硬件加速能力、图形引擎中存在许多低效算法和代码质量较差。
- OpenGUI 最初的名字叫FastGL,支持多种操作系统平台。OpenGUI分三层。最低层是由汇编写的快速图形引擎;中间层提供了图形绘制API;第三层用C++编写的,提供了完整的GUI对象集。基于汇编实现的内核并利用MMX指令提高运行速度,比较适合于基于x86平台的实时系统,可移植性稍差。
- Qt/Embedded 是著名的Qt库开发商TrollTech正在进行的基于framebufer的面向嵌入式系统的Qt版本。由于KDE等项目使用Qt作为支持库,所以由许多基于Qt的X Windows程序可以非常方便地移植到Qt/Embedded版本上。因其面向对象、跨平台和界面设计更美观而得到广泛的应用。美中不足是其C++接口对某些应用来讲比较臃肿,而且如果在商品化产品中使用这个库,对硬件的性能要求比较高。
2 Qt/Embedded应用程序基本开发流程 Qt/Embedded开放了源代码,使得开发人员可以在GPL许可协议下自由地使用Qt/Embedded进行嵌入式Linux应用系统的开发。源代码可以从Trollteeh的官方网站上下载到。而且在Tmake、Qmake、QVFB和Qt Designer等众多强大开发工具的支持下,大大提高了Qt/Embedded系统的开发效率和项目进度,具体步骤大致如下: - Qt Designer是设计窗口组件(Widget)的应用程序,在安装Qt的bin目录下键入./designer,将启动一个包含很多Qt组件的可视化界面。在此组织应用程序的各组件分布很方便,最后可生成一个file.ui和main.cpp文件;file.ui是用XML语言写的一个文本。
- Uic(User Interface Compiler)是从XML文件生成代码的用户界面编译器,用来将file.ui文件生成file.h和file.cpp文件(命令如:uic -o file.h file.ui uic -o file.cpp -i file.h file.ui),但生成的这两个文件不是标准的纯C++代码.通常称为Qt的c++扩展.因为Qt的对象问中运用了信号/槽的通信机制,在文件中用Q_OBJECT宏来标识。
- 用qmake工具生成file.pro文件,在设置好环境变量后,用tmake工具生成Makefile文件(tmake是跨平台Makefile生成器);不管在Pc环境、Qt/Embedded环境还是交叉编译环境中都能生成相应的Makefile文件。
- moc(元对象编译器)用来解析一个C++文件中的类声明并且生成初始化对象的c++代码,moc在读取c++源文件,如果发现其中一个或多个类的声明中含有Q_OBJECT宏,就给出这个使用Q_OBJECT宏的类生成另外一个包含元对象代码的C++元文件;元对象代码对信号/槽机制、运行时类型信息和动态属性系统是需要的。
- 用make命令生成可执行的二进制代码文件;由于使用tmake生成Makefile文件,当需要的时候,编译规则中包含调用moc(元对象编辑器),自动地被连编系统调用,不需要手工调用。
3 一个应用程序实现的关键技术 3.1 PhotoAlbum应用程序背景简介 我们实现的一个多功能电话系统的内核是采用2.4.18版的ARMLinux 内核,并在此基础上加以改写,运行在三星s3c2410 微处理器上,目标系统上配有两个特制的键盘和一块240×480的4bbp(bit per pixel)的LCD:小键盘的功能是用于拔电话号码和应用程序的快捷键,大键盘主要是用来进行文本编辑等,功能类似于Pc键盘;LCD用于显示基于Qt/Embedded的所有图形应用程序。多功能电话的主要功能:来电显示、电话录音、浏览网页、收发邮件、在线聊天和浏览图片即PhotoAlbum等功能。其中编写的键盘驱动和TAD驱动是电话功能实现的主要基础。应用程序PhotoAlbum主要有三个方面的功能:实现对单个图片的简单浏览、在多个图片的情况下实现对所有图片依次浏览和PhotoAlbum与其它应用程序之间的数据交流。
3.2 单个图片的浏览功能 此功能主要是实现对一个图片的简单浏览:图片放大、缩小和图片的垂直和水平旋转,以下提出了两种实现方法。 1)Qt中QPainter类是一个底层的画图类,主要负责Qt在Widgets中的各类绘画,通常在设备的自身坐标系统(一般是像素)上操作,但是也很好地支持坐标转换;QDirectPainter继承于QPainter类。此类可以跟可视硬件进行直接通信,指向framebuffer的内存区。Qlnrage和QPixmap类提供了对图片的处理,但是不支持摄像头摄取的数据类型操作。QPainter类提供了两个绘制像素映射图像的函数drawImage()和drawPixmap()。 DrawPixmap()函数能把pixmap的一部分或整个复制到绘制设备中;drawImage()能把图片绘制在绘制设备中,但drawPixmap()在屏幕上会更快一些,可使用convertFromlmage()将图片转换为像素映射。QWMatrix类提供对二维坐标系统的转换,与QPainter类结合来改变图像的显示逻辑。 下面一段程序是实现对单个图片的显示过程: QWMatdx um; Xdegree=Xdegree-16.0; //图片每次移动的距离; m.translate(Xdegree,Ydegree); //移动图片; m.rotate(cwdegree); //旋转图片; m.scale(zoomdegree,zoomdegree); //放大缩小图片; //以下代码是实现编辑后的图片显示: QPixmap pm; if(pm.load("image.any")) //装入欲显示图片; { QPainter p; QRect r; r.setRect(0,0,400,400); //设定图片显示区域的形状; r.moveTopLeft(QPoint(-r,width()/2,-r,height()/2));//移动图片; p.begin(&pm); //准备画图; p.setWorldMatrix(um); //得到设置好显示格式的图片; p.drawPixmap(-pm.width()/2,-pm.height()/2,pix);//执行画图; p.end(); //画图结束; } return; //函数返回;
2)QCanvasView类给QCanvas类提供了一个屏幕显示,QCanvaItem类在QCanvas类上提供了一个抽象的视图对象,一个canvas能被添加多个canvas item,QCanvasRectangle类规定了在QCanvas类提供的画布上以长方形画出内容,这里QCanvasRectangle类的对象就是一个callvas item,canvas中的所有item都由QCanvasItemList类来管理,QCanvasItem类中的函数moveBy()可用来移动canvans中的某个指定的item。 QImage类中函数mirror(bood,bool),能生成一个翻转后的图片,其中的两个参数分别表示图片的水平和垂直方向的翻转,类QImage中的函数smoothScale(),用来设置图片的大小,从而达到图片放大缩小的功能。最终图片是使用QCanvasRectangle类作为一个canvas item绘制在canvas上,调用QCanvasItem类中的show()显示图片。如smallImg=img.smoothScale(int(img.width()*0.75),int (img.heigth()*0.75))功能是把img图片缩小四分之一,传给smallImg(smallImage和img都是QImage类型)。 上述两种方法都实现了PhotoAlbum应用程序所需的功能,QCanvasView类和QPainter类分别提供了对图片的显示方法。但是QPainter类的实现更加底层,对硬件的配置比较敏感,而且每次只能对单个图片进行显示和管理;而QCanvasView类比QPainter类更高级易用,能同时显示多张图片,类似于微型的图片管理容器,能组织管理多张图片的显示。而且用QPainter类画出来的图片没有分层的概念。
3.3 多个图片的幻灯片功能 其实只要对一个图片的显示成功后,对多个图片的幻灯显示就顺理成章了,Qt/Embedded中有个QTimer类,提供了基于时间段的信号/槽机制。类似于定时器的功能。 QTimer *counter=new QTime(this); //声明一个定时器: connect(counter,SIGNALE(timeout()),this,SLOT(changeImage())); //建立信号与相关槽的对应; counter->start(2000); //每隔两秒执行一次changeImage()函数; 在changImage()函数中执行改变显示图片的名称和运行update()函数,而update()函数的执行会自动调用paintEvent(QPaintEvent *)函数(update()与paintEvent()的信号/槽机制是Qt/Embedded默认的),paintEvent()进行画图,这样Slide的效果就实现了。
3.4 程序间图片数据交流 Emailer与PhotoMbum 两应用程序之间需互通信息,即Emailer中的图片能用PhotoAlbum来浏览,PhotoAlbum中的图片能作为附件在Emailer中发送;在Qt/Embedded中,QCopchannel类提供了在客户机程序(clients)间的通信能力,QCOP是在不同程序问使用相同的地址空间进行通信的一种通信协议,这种机制现在仅被使用在Qt/Embedded中,消息的接收方要先注册QCopChannel类,注册同时即给出自己的身份标识名称。receive (const QCString,const QByteArray)函数用来接收传进来的消息,第一个参数是标记传输给的对象,第二个参数是实际的值;消息的发送方不需要先注册QCopChannel类,QCopChannel类中的isRegistered()函数用来检测消息的被发送方是否注册,send (const QCString &channel,const QCString &msg)也可以是消息的接收方,而且能同时注册几个QCopehannel类的对象;这样Emailer与PhotoAlbum两应用程序之间可以进行自由的通信。
3.5 调试 为了在目标平台上能顺利的运行PhotoAlbum程序,并实现所要求的功能,我们先在开发机上用Qt/Embedded提供的模拟环境qvfb(qt virtual framebuffer)即Qt/Embedded的虚拟仿真窗口中进行测试。在qvfb中可以进行虚拟帧缓冲的宽度高度色深和X11光标的显示等属性进行设置。在测试过程中发现,将虚拟帧缓冲的包深调至为4bbp时(因为目标平台LCD的色深是4bbp),在PhotoAlbum应用程序中图片的简单浏览功能都基本实现,只是图片显示出来的是黑白效果。在测试工程中发现当把qvfb的虚拟帧缓冲的色深凋至为8bbp时,图片显示的彩色效果较好。把PhotoAlbum应用程序下载到目标平台上去时,情况与在qvfb上的虚拟帧缓冲的色深调至为4bbp时相似,所以Qt提供的qvfb是个很好的运行环境模拟器,由于不需每次测试都把程序下载到目标平台上,大大缩减了应用程序的开发时间。 4 结束语 笔者发现,在对PhotoAlbum应用程序的图片进行90度倍数的旋转而不是垂直和水平旋转时,在开发平台的qvfb环境下测试没能通过,且终端有"QPixmap::PhotoAlbum:Display not supported(bbp=4);setMask;the pixmap and the mask must have the same size" 等提示,但当把qvfb的虚拟帧缓冲的色深凋至为8bbp时,能运行成功。出现这种现象,可能与Qt/Embedded的内部源代码的实现机制有关。 Qt/Embedded图形一般支持GIF、BMP、PPM、XMP等格式的图像,在默认情况下不支持JPG格式,在Qtopia和Opic中,它们的定位是在高端产品上,对图片的支持格式很多,其中默认情况下包括JPG格式,运行的默认虚拟帧缓冲的色深是32时环境的要求比较高,而且Qt/Embedded当虚拟帧缓冲的色深上到16时,应用程序就不能驱动,终端提示"Cant't drive depth16"。 由于Qt/Embedded的图形库较大,对硬件的环境要求比较高,在目标平台上显示图片,如果图片本身比较大,显示所花的时间间隔很长。在图片的显示过程中有明显的晃动,如果在这样的低端平台上对图片进行复杂处理,即使能正常显示,效果也会不理想。所以在低端平台的产品上有时增加复杂的图形功能,不是太适合。
|