最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

第12章Qt图形编程

来源:动视网 责编:小OO 时间:2025-10-03 00:31:33
文档

第12章Qt图形编程

“黑色经典”系列之《嵌入式Linux应用程序开发详解》Linux设备驱动程序的基本功能常见设备驱动接口函数掌握键盘设备驱动程序编写步骤华清远见培训教材12.1嵌入式GUI简介目前的桌面机操作系统大多有着美观、操作方便、功能齐全的GUI(图形用户界面),例如KDE或者GNOME。GUI(图形用户界面)是指计算机与其使用者之间的对话接口,可以说,GUI是当今计算机技术的重大成就。它的存在为使用者提供了友好便利的界面,并大大地方便了非专业用户的使用,使得人们从繁琐的命令中解脱出来,可以通过窗口、菜单
推荐度:
导读“黑色经典”系列之《嵌入式Linux应用程序开发详解》Linux设备驱动程序的基本功能常见设备驱动接口函数掌握键盘设备驱动程序编写步骤华清远见培训教材12.1嵌入式GUI简介目前的桌面机操作系统大多有着美观、操作方便、功能齐全的GUI(图形用户界面),例如KDE或者GNOME。GUI(图形用户界面)是指计算机与其使用者之间的对话接口,可以说,GUI是当今计算机技术的重大成就。它的存在为使用者提供了友好便利的界面,并大大地方便了非专业用户的使用,使得人们从繁琐的命令中解脱出来,可以通过窗口、菜单
“黑色经典”系列之《嵌入式Linux应用程序开发详解》

Linux设备驱动程序的基本功能

常见设备驱动接口函数

掌握键盘设备驱动程序编写步骤

华清远见<嵌入式Linux应用开发班>培训教材12.1 嵌入式GUI简介

目前的桌面机操作系统大多有着美观、操作方便、功能齐全的GUI(图形用户界面),例如KDE或者GNOME。GUI(图形用户界面)是指计算机与其使用者之间的对话接口,可以说,GUI是当今计算机技术的重大成就。它的存在为使用者提供了友好便利的界面,并大大地方便了非专业用户的使用,使得人们从繁琐的命令中解脱出来,可以通过窗口、菜单方便地进行操作。

而在嵌入式系统中,GUI的地位也越来越重要,但是不同于桌面机系统,嵌入式GUI 要求简单、直观、可靠、占用资源小且反应快速,以适应系统硬件资源有限的条件。另外,由于嵌入式系统硬件本身的特殊性,嵌入式GUI应具备高度可移植性与可裁减性,以适应不同的硬件条件和使用需求。总体来讲,嵌入式GUI具备以下特点:

•体积小;

•运行时耗用系统资源小;

•上层接口与硬件无关,高度可移植;

•高可靠性;

•在某些应用场合应具备实时性。

UNIX环境下的图形视窗标准为X Window System,Linux是类UNIX系统,所以顶层运行的GUI系统是兼容X标准的XFree86系统。X标准大致可以划分X Server、Graphic Library (底层绘图函数库)、Toolkits、Window Manager等几大部分。其好处是具有可扩展性、可移植性等优点,但对于嵌入式系统而言无疑太过庞大、累赘、低效。目前流行的嵌入式GUI与X思路不同,这些GUI一般不局限于X标准,更强调系统的空间和效率。

12.1.1 Qt/Embedded

表12.1归纳了Qt/Embedded的一些优缺点

表12.1 Qt/Embedded分析

Qt/Embedded分析

以开发包形式提供包括了图形设计器,Makefile 制作工具,字体国际化工具,Qt的C++类库等

跨平台支持Microsoft Windows 95/98/2000、Microsoft Windows NT、MacOS X、Linux、Solaris、HP-UX、Tru (Digital UNIX)、Irix、FreeBSD、BSD/OS、SCO、AIX等众多平台

类库支持跨平台Qt类库封装了适应不同操作系统的访问细节,这正是Qt的魅力所在优点

模块化可以任意裁减

缺点结构也过于复杂臃

肿,很难进行底层

的扩充、定制和移

例如:

•尽管Qt/Embedded声称它最小可以裁剪到630KB,但这时的Qt/Embedded

库已经基本失去了使用价值

•它提供的控件集沿用了PC风格,并不太适合许多手持设备的操作要求

•Qt/Embedded的底层图形引擎只能采用framebuffer,只能针对高端嵌入

式图形领域的应用而设计的

•由于该库的代码追求面面俱到,以增加它对多种硬件设备的支持,造成

了其底层代码比较凌乱,各种补丁较多的问题

华清远见<嵌入式Linux应用开发班>培训教材12.1.2 MiniGUI

提起国内的开源软件,就肯定会提到MiniGUI,它由魏永明先生和众多志愿者开发,是一个基于Linux的实时嵌入式系统的轻量级图形用户界面支持系统。

MiniGUI分为最底层的GAL层和IAL层,向上为基于标准POSIX接口中pthread库的Mini-thread架构和基于Server/Client的Mini-Lite架构。其中前者受限于thread模式对于整个系统的可靠性影响——进程中某个thread的意外错误可能导致整个进程的崩溃,该架构应用于系统功能较为单一的场合。Mini-Lite应用于多进程的应用场合,采用多进程运行方式设计的Server/Client架构能够较好地解决各个进程之间的窗口管理、Z序剪切等问题。MiniGUI还有一种从Mini-Lite衍生出的standalone运行模式。与Lite架构不同的是,standalone模式一次只能以窗口最大化的方式显示一个窗口。这在显示屏尺寸较小的应用场合具有一定的应用意义。

MiniGUI的IAL层技术SVGA lib、LibGGI、基于framebuffer的native图形引擎以及哑图形引擎等,对于Trolltech公司的QVFB在X Window下也有较好的支持。IAL层则支持Linux 标准控制台下的GPM鼠标服务、触摸屏、标准键盘等。

MiniGUI下丰富的控件资源也是MiniGUI的特点之一。当前MiniGUI的最新版本是1.3.3。在该版本的控件中已经添加了窗口皮肤、工具条等桌面GUI中的高级控件支持。对比其他系统,“Mini”是MiniGUI的特色,轻量、高性能和高效率的MiniGUI已经应用在电视机顶盒、实时控制系统、掌上电脑等诸多场合。

12.1.3 Microwindows、Tiny X等

Microwindows Open Source Project成立的宗旨在于针对体积小的装置,建立一套先进的视窗环境,在Linux桌面上通过交叉编译可以很容易地制作出Microwindows的程序。Microwindows能够在没有任何操作系统或其他图形系统的支持下运行,它能对裸显示设备进行直接操作。这样Microwindows就显得十分小巧,便于移植到各种硬件和软件系统上。

然而Microwindows的免费版本进展一直很慢,几乎处于停顿状态,而且至今为止,国内没有任何一家对Microwindows提供全面技术支持、服务和担保的专业公司。

Tiny X Server是XFree86 Project的一部分,由Keith Pachard发展起来的,而他本身就是XFree86专案的核心成员之一。一般的X Server都太过于庞大,因此Keith Packard就以XFree86为基础,精简而成Tiny X Server,它的体积可以小到几百KB而已,非常适合应用于嵌入式环境。

就纯X Window System搭配Tiny X Server架构来说,其最大的优点就是具有很好的弹性开发机制,并能大大提高开发速度。因为与桌面的X架构相同,因此相对于很多以Qt、GTK+、FLTK等为基础开发的软件可以很容易地移植上来。

虽然移植方便,但是却有体积大的缺点,由于很多软件本来是针对桌面环境开发的,因此无形之中具备了桌面环境中很多复杂的功能。因此“调校”变成采用此架构最大的课题,有时候重新改写都可能比调校所需的时间还短。

表12.2所示总结了常见GUI的参数比较。

>培训教材

华清远见<嵌入式Linux 应用开发班>培训教材

表12.2

常见GUI 参数比较

12.2 Qt/Embedded 开发入门

12.2.1 Qt/Embedded 介绍

1.架构

Qt/Embedded 以原始Qt 环境。Qt/Embedded 通过Qt API 与Linux I/O 设施Qt/X11相比,Qt/Embedded 很省内存,因为它不需要一个X lib ,采用framebuffer (帧缓冲)作为底层图形接口。同mouse 输入事件。Qt/Embedde 的应用程序可以直接写内核系统。图12.1所示比较了Qt/Embedded 与Qt/X11图12.1 Qt/Embedded 与Qt/X11的Linux 版本的比较

使用单一的API 进行跨平台的编程可以有很多好处。提供嵌入式设备和桌面计算机环境下应用的公司可以培训开发人员使用同一套工具开发包,这有利于开发人员之间共享开发经验与知识,也使得管理人员在分配开发人员到项目中的时候增加灵活性。更进一步来说,针对某个平台而开发的应用和组件也可以销售到Qt 支持的其他平台上,从而以低廉的成本扩大

(1)窗口系统

一个Qt/Embedded窗口系统包含了一个或多个进程,其中的一个进程可作为服务器。该服务进程会分配客户显示区域,以及产生鼠标和键盘事件。该服务进程还能够提供输入方法和一个用户接口给运行起来的客户应用程序。该服务进程其实就是一个有某些额外权限的客户进程。任何程序都可以在命令行上加上“-qws”的选项来把它作为一个服务器运行。

客户与服务器之间的通信使用共享内存的方法实现,通信量应该保持最小,例如客户进程直接访问帧缓冲来完成全部的绘制操作,而不会通过服务器,客户程序需要负责绘制它们自己的标题栏和其他式样。这就是Qt/Embedded库内部层次分明的处理过程。客户可以使用QCOP通道交换消息。服务进程简单的广播QCOP消息给所有监听指定通道的应用进程,接着应用进程可以把一个插槽连接到一个负责接收的信号上,从而对消息做出响应。消息的传递通常伴随着二进制数据的传输,这是通过一个QDataStream类的序列化过程来实现的,有关这个类的的描述,请读者参考相关资料。

QProcess类提供了另外一种异步的进程间通信机制。它用于启动一个外部的程序并且通过写一个标准的输入和读取外部程序的标准输出和错误码来和它们通信。

(2)字体

Qt/Embedded支持四种不同的字体格式:True Type字体(TTF),Postscript Type1字体,位图发布字体(BDF)和Qt的预呈现(Pre-rendered)字体(QPF)。Qt还可以通过增加Qfont- Factory的子类来支持其他字体,也可以支持以插件方式出现的反别名字体。

每个TTF或者TYPE1类型的字体首次在图形或者文本方式的环境下被使用时,这些字体的字形都会以指定的大小被预先呈现出来,呈现的结果会被缓冲。根据给定的字体尺寸(例如10或12点阵)预先呈现TTF或者TYPE1类型的字体文件并把结果以QPF的格式保存起来,这样可以节省内存和CPU的处理时间。QPF文件包含了一些必要的字体,这些字体可以通过makeqpf工具取得,或者通过运行程序时加上“-savefonts”选项获取。如果应用程序中使用到的字体都是QPF格式,那么Qt/Embedded将被重新配置,并排除对TTF和TYPE1类型的字体的编译,这样就可以减少Qt/Embedded的库的大小和存储字体的空间。例如一个10点阵大小的包含所有ASII字符的QPF字体文件的大小为1300Byte,这个文件可以直接从物理存储格式映射成为内存存储格式。

Qt/Embedded的字体通常包括Unicode字体的一部分子集,ASII和Latin-1。一个完整的16点阵的Unicode字体的存储空间通常超过1MB,我们应尽可能存储一个字体的子集,而不是存储所有的字,例如在一个应用中,仅仅需要以Cappuccino字体、粗体的方式显示产品的名称,但是却有一个包含了全部字形的字体文件。

(3)输入设备及输入法

Qt/Embedded 3.0支持几种鼠标协议:BusMouse、IntelliMouse,Microsoft和MouseMan.Qt/ Embedded还支持NECVr41XX和iPAQ的触摸屏。通过从QWSMouseHandler或者Qcalibra- tedMouseHandler派生子类,开发人员可以让Qt/Embedded支持更多的客户指示设备。

Qt/Embedded支持标准的101键盘和Vr41XX按键,通过子类化QWSKeyboardHandler 可以让Qt/Embedded支持更多的客户键盘和其他的非指示设备。

对于非拉丁语系字符(例如阿拉伯,中文,希伯来和日语)的输入法,需要把它写成过

>培训教材滤器的方式,并改变键盘的输入。输入法的作者应该对全部的Qt API的使用有完全的认识。在一个无键盘的设备上,输入法成了惟一的输入字符的手段。Qtpia提供了4种输入方法:笔迹识别器、图形化的标准键盘、Unicode键盘和居于字典方式提取的键盘。

(4)屏幕加速

通过子类化QScreen和QgfxRaster可以实现硬件加速,从而为屏幕操作带来好处。Troll- tech提供了Mach和V oodoo3视频卡的硬件加速的驱动例子,同时可以按照协议编写其他的驱动程序。

2.Qt的开发环境

Qt/Embedded的开发环境可以取代那些我们熟知的UNIX和Windows开发工具。它提供了几个跨平台的工具使得开发变得迅速和方便,尤其是它的图形设计器。UNIX下的开发者可以在PC机或者工作站使用虚拟缓冲帧,从而可以模仿一个和嵌入式设备的显示终端大小,像素相同的显示环境。

嵌入式设备的应用可以在安装了一个跨平台开发工具链的不同的平台上编译。最通常的做法是在一个UNIX系统上安装跨平台的带有libc库的GNU C++编译器和二进制工具。在开发的许多阶段,一个可替代的做法是使用Qt的桌面版本,例如通过Qt/X11或是Qt/Windows来进行开发。这样开发人员就可以使用他们熟悉的开发环境,例如微软公司的Visual C++或者Borland C++。在UNIX操作系统下,许多环境也是可用的,例如Kdevelop,它也支持交互式开发。

如果Qt/Embedded的应用是在UNIX平台下开发的话,那么它就可以在开发的机器上以一个的控制台或者虚拟缓冲帧的方式来运行,对于后者来说,其实是有一个X11的应用程序虚拟了一个缓冲帧。通过指定显示设备的宽度,高度和颜色深度,虚拟出来的缓冲帧将和物理的显示设备在每个像素上保持一致。这样每次调试应用时开发人员就不用总是刷新嵌入式设备的FLASH存储空间,从而加速了应用的编译、链接和运行周期。运行Qt的虚拟缓冲帧工具的方法是在Linux的图形模式下运行以下命令:

qvfb (回车)

当Qt嵌入式的应用程序要把显示结果输出到虚拟缓冲帧时,我们在命令行运行这个程序时,在程序名后加上-qws的选项。例如:$> hello–qws。

3.Qt的支撑工具

Qt包含了许多支持嵌入式系统开发的工具,有两个最实用的工具是qmake和Qt designer (图形设计器)。

•qmake是一个为编译Qt/Embedded库和应用而提供的Makefile生成器。它能够根据一个工程文件(.pro)产生不同平台下的Makefile文件。qmake支持跨平台开发和影子生成(影子生成是指当工程的源代码共享给网络上的多台机器时,每台机器编译链接这个工程的代码将在不同的子路径下完成,这样就不会覆盖别人的编译链接生成的文件。qmake还易于在不同的配置之间切换。)

•Qt图形设计器可以使开发者可视化地设计对话框而不需编写代码。使用Qt图形设计器的布局管理可以生成能平滑改变尺寸的对话框。

华清远见<嵌入式Linux应用开发班>培训教材

qmake和Qt图形设计器是完全集成在一起的。

12.2.2 Qt/Embedded信号和插槽机制

1.机制概述

信号和插槽机制是Qt的核心机制,要精通Qt编程就必须对信号和插槽有所了解。信号和插槽是一种高级接口,应用于对象之间的通信,它是Qt的核心特性,也是Qt区别于其他工具包的重要地方。信号和插槽是Qt自行定义的一种通信机制,它于标准的C/C++语言,因此要正确的处理信号和插槽,必须借助一个称为moc(Meta Object Compiler)的Qt工具,该工具是一个C++预处理程序,它为高层次的事件处理自动生成所需要的附加代码。

所谓图形用户接口的应用就是要对用户的动作做出响应。例如,当用户单击了一个菜单项或是工具栏的按钮时,应用程序会执行某些代码。大部分情况下,是希望不同类型的对象之间能够进行通信。程序员必须把事件和相关代码联系起来,这样才能对事件做出响应。以前的工具开发包使用的事件响应机制是易崩溃的,不够健壮的,同时也不是面向对象的。

以前,当使用回调函数机制把某段响应代码和一个按钮的动作相关联时,通常把那段响应代码写成一个函数,然后把这个函数的地址指针传给按钮,当那个按钮被单击时,这个函数就会被执行。对于这种方式,以前的开发包不能够确保回调函数被执行时所传递进来的函数参数就是正确的类型,因此容易造成进程崩溃。另外一个问题是,回调这种方式紧紧地绑定了图形用户接口的功能元素,因而很难开发进行的分类。

信号与插槽机制是不同的。它是一种强有力的对象间通信机制,完全可以取代原始的回调和消息映射机制。在Qt中信号和插槽取代了那些上述这些凌乱的函数指针,使得用户编写这些通信程序更为简洁明了。信号和插槽能携带任意数量和任意类型的参数,他们是类型完全安全的,因此不会像回调函数那样产生core dumps。

所有从QObject或其子类(例如Qwidget)派生的类都能够包含信号和插槽。当对象改变状态时,信号就由该对象发射(emit)出去了,这就是对象所要做的全部工作,它不知道另一端是谁在接收这个信号。这就是真正的信息封装,它确保对象被当作一个真正的软件组件来使用。插槽用于接收信号,但它们是普通的对象成员函数。一个插槽并不知道是否有任何信号与自己相连接。而且,对象并不了解具体的通信机制。

用户可以将很多信号与单个插槽进行连接,也可以将单个信号与很多插槽进行连接,甚至将一个信号与另外一个信号相连接也是可能的,这时无论第一个信号什么时候发射,系统都将立刻发射第二个信号。总之,信号与插槽构造了一个强大的部件编程机制。

图12.2所示表示了对象间信号与插槽之间的关系。

>培训教材

2

(1)

当某。只有定义了这个关联的插槽将被立GUI事件循环。只信号相关联,那么,当这个信号被发射时,这些槽将会一个接一个地执行,但是它们执行的顺序将会是随机的、不确定的,用户不能人为地指定哪个先执行、哪个后执行。

Qt的signals关键字指出进入了信号声明区,随后即可声明自己的信号。例如,下面定义了3个信号:

signals:

void mySignal();

void mySignal(int x);

void mySignalParam(int x,int y);

在上面的定义中,signals是Qt的关键字,而非C/C++的。接下来的一行void mySignal()定义了信号mySignal,这个信号没有携带参数;接下来的一行void mySignal(int x)定义了重名信号mySignal,但是它携带一个整形参数,这有点类似于C++中的虚函数。从形式上讲信号的声明与普通的C++函数是一样的,但是信号却没有函数体定义。另外,信号的返回类型

都是void。信号由moc自动产生,它们不应该在.cpp文件中实现。

华清远见<嵌入式Linux应用开发班>培训教材(2)插槽

插槽是普通的C++成员函数,可以被正常调用,它们惟一的特殊性就是很多信号可以与其相关联。当与其关联的信号被发射时,这个插槽就会被调用。插槽可以有参数,但插槽的参数不能有缺省值。

既然插槽是普通的成员函数,因此与其他的函数一样,它们也有存取权限。插槽的存取权限决定了谁能够与其相关联。同普通的C++成员函数一样,插槽函数也分为3种类型,即public slots、private slots和protected slots。

•public slots:在这个区内声明的槽意味着任何对象都可将信号与之相连接。这对于组件编程非常有用,用户可以创建彼此互不了解的对象,将它们的信号与槽进行连接以便信息能够正确地传递。

•protected slots:在这个区内声明的槽意味着当前类及其子类可以将信号与之相连接。这适用于那些槽,它们是类实现的一部分,但是其界面接口却面向外部。

•private slots:在这个区内声明的槽意味着只有类自己可以将信号与之相连接。这适用于联系非常紧密的类。

bool QObject::connect ( const QObject * sender, const char * signal,const QObject * receiver, const char * member ) [static]

这个函数的作用就是将发射者sender对象中的信号signal与接收者receiver中的member 插槽函数联系起来。当指定信号signal时必须使用Qt的宏SIGNAL(),当指定插槽函数时必须使用宏SLOT()。如果发射者与接收者属于同一个对象的话,那么在connect调用中接收者参数可以省略。

•信号与插槽相关联

下例定义了两个对象:标签对象label和滚动条对象scroll,并将valueChanged()信号与标签对象的setNum()插槽函数相关联,另外信号还携带了一个整型参数,这样标签总是显示滚动条所处位置的值。

QLabel *label = new QLabel;

QScrollBar *scroll = new QScrollBar;

QObject::connect( scroll, SIGNAL(valueChanged(int)),label,SLOT(setNum(int)) );

>培训教材•信号与信号相关联

在下面的构造函数中,MyWidget创建了一个私有的按钮aButton,按钮的单击事件产生的信号clicked()与另外一个信号aSignal()进行了关联。这样,当信号clicked()被发射时,信号aSignal()也接着被发射。如下所示:

义如下所示:

bool QObject::disconnect ( const QObject * sender, const char * signal,const Object * receiver, const char * member ) [static]

这个函数断开发射者中的信号与接收者中的槽函数之间的关联。

有3种情况必须使用disconnect()函数。

•断开与某个对象相关联的任何对象

当用户在某个对象中定义了一个或者多个信号,这些信号与另外若干个对象中的槽相关联,如果想要切断这些关联的话,就可以利用这个方法,非常之简洁。如下所示:

disconnect( myObject, 0, 0, 0 )

或者

myObject->disconnect()

•断开与某个特定信号的任何关联

华清远见<嵌入式Linux应用开发班>培训教材这种情况是非常常见的,其典型用法如下所示:disconnect( myObject, SIGNAL(mySignal()), 0, 0 ) 或者

myObject->disconnect( SIGNAL(mySignal()) )

•断开两个对象之间的关联

这也是非常常用的情况,如下所示:

disconnect( myObject, 0, myReceiver, 0 )

或者

myObject->disconnect( myReceiver )

注意

在disconnect函数中0可以用作一个通配符,分别表示任何信号、任何接收对象、接收对象中

的任何槽函数。但是发射者sender不能为0,其他3个参数的值可以等于0。

12.2.3 搭建Qt/Embedded开发环境

一般来说,用Qt/Embedded开发的应用程序最终会发布到安装有嵌入式Linux操作系统的小型设备上,所以使用装有Linux操作系统的PC机或者工作站来完成Qt/Embedded开发当然是最理想的环境,此外Qt/Embedded也可以安装在UNIX或Windows系统上。这里就以安装到Linux操作系统为例进行介绍。

这里需要有3个软件安装包:tmake工具安装包,Qt/Embedded安装包,Qt的X11版的安装包。

•tmake1.11或更高版本:生成Qt/Embedded应用工程的Makefile文件。

•Qt/Embedded:Qt/Embedded安装包。

•Qt 2.3.2 for X11:Qt的X11版的安装包,产生x11开发环境所需要的两

个工具。

注意

这些软件安装包都有许多不同的版本,由于版本的不同会导致这些软件在使用时可能引起的冲

突,为此必须依照一定的安装原则,Qt/Embedded安装包的版本必须比Qt for X11的安装包的

版本新,这是因为Qt for X11的安装包中的两个工具uic和designer产生的源文件会和

Qt/Embedded的库一起被编译链接,因此要本着“向前兼容”的原则,Qt for X11 的版本应比

Qt/Embedded的版本旧。

1.安装tmake

用户可使用普通的解压缩即可,注意要将路径添加到全局变量中去,如下所示:

tar zxvf tmake-1.11.tar.gz

export TMAKEDIR=$PWD/tmake-1.11

export TMAKEPATH=$TMAKEDIR/lib/qws/linux-x86-g++

export PATH=$TMAKEDIR/bin:$PATH

2.安装Qt/Embedded 2.3.7

这里使用常见的解压命令及安装命令即可,要注意这里的路径与不同的系统有关,读者

>培训教材要根据实际情况进行修改。另外,这里的configure命令带有参数“-qconfig –qvfb –depths 4816,32”分别为指定Qt嵌入式开发包生成虚拟缓冲帧工具qvfb,并支持4,8,16,32 位的显示颜色深度。另外读者也可以在configure的参数中添加“-system”、“-jpeg”或“gif”命令,使Qt/Embedded平台能支持jpeg、gif格式的图形。

Qt/Embedded开发包有5种编译范围的选项,使用这些选项可控制Qt生成的库文件的大小。如命令make sub-src指定按精简方式编译开发包,也就是说有些Qt类未被编译。其他编译选项的具体用法可参见“./configure–help”命令查看。精简方式的安装步骤若下所示:

12.2.4 Qt/Embedded窗口部件

QT提供了一整套的窗口部件。它们组合起来可用于创建用户界面的可视元素。按钮、菜单、滚动条、消息框和应用程序窗口都是窗口部件的实例。因为所有的窗口部件既是控件又是容器,因此QT的窗口部件不能任意地分为控件和容器。通过子类化已存在的QT部件或少数时候必要的全新创建,自定义的窗口部件能很容易地创建出来。

窗口部件是QWidget或其子类的实例,用户自定义的窗口通过子类化得到。如下图12.3

华清远见<嵌入式Linux应用开发班>培训教材

所示:

图12.3 源自QWidget的类层次结构

一个窗口部件可包含任意数量的子部件。子部件在父部件的区域内显示。没有父部件的

下图12.4是该Hello窗口的运行效果图:

2.常见通用窗口组合

Qt中还有一些常见的通用窗口,它们使用了Windows风格显示。如下图12.5、12.6、12.7、12.8分别描述了常见的一些通用窗口的组合使用。

>培训教材华清远见<嵌入式Linux应用开发班>培训教材

函数,带有可选parent和name参数的(如果设置了name参数测试和调试会更容易)。系统有规律地调用从QObject继承的timerEvent()函数。

它在clock.h中定义如下所示:

#include

class Clock:public QLCDNumber

{

public:

Clock(QWidget *parent=0,const char *name=0);

protected:

void timerEvent(QTimerEvent *event);

private:

void showTime();

bool showingColon;

};

>培训教材文件clock.h和clock.cpp完整地声明并实现了Clock部件。

#include

#include "clock.h"

int main(int argc,char **argv)

{

QApplication app(argc,argv);

Clock *clock=new Clock;

app.setMainWidget(clock);

clock->show();

return app.exec();

}

12.2.5 Qt/Embedded图形界面编程

Qt提供了所有可能的类和函数来创建GUI程序。Qt既可用来创建“主窗口”式的程序,即一个有菜单栏,工具栏和状态栏作为环绕的中心区域;也可以用来创建“对话框”式的程序,使用按钮和必要的选项卡来呈现选项与信息。Qt支持SDI(单文档界面)和MDI(多文档界面)。Qt还支持拖动,放下和剪贴板。工具栏可以在工具栏区域内移动,拖拽到其他区域或者作为工具托盘浮动起来。这个功能是内建的,不需要额外的代码,但程序员在需要时可以将约束工具栏的行为。

使用Qt可以大大简化编程程序。例如,如果一个菜单项,一个工具栏按钮和一个快捷键都完成同样的动作,那么这个动作只需要一份代码。

Qt还提供消息框和一系列标准对话框,使得程序向用户提问和让用户选择文件、文件夹、字体以及颜色变得更加简单。为了呈现一个消息框或一个标准对话框,只需要用一个使用一个方便的Qt静态函数的一行的语句。

1.主窗口类

QMainWindow类提供了一个典型应用程序的主窗口框架。

一个主窗口包含了一组标准窗体的集合。主窗口的顶部包含一个菜单栏,它的下方放置着一个工具栏,工具栏可以移动到其他的停靠区域。主窗口允许停靠的位置有顶部、左边、右边和底部。工具栏可以被拖放到一个停靠的位置,从而形成一个浮动的工具面板。主窗口的下方,也就是在底部的停靠位置下方有一个状态栏。主窗口的中间区域可以包含其他的窗体。提示工具和“这是什么”帮助按钮以旁述的方式阐述了用户接口的使用方法。

对于小屏幕的设备,使用Qt图形设计器定义的标准的Qwidget模板比使用主窗口类更好一些。典型的模板包含有菜单栏、工具栏,可能没有状态栏(在必要的情况下,可以用任务栏,标题栏来显示状态)。

例如,一个文本编辑器可以把QTextEdit作为中心部件:

QTextEdit *editor=new QTextEdit(mainWindow);

mainWindow->setCentralWidget(editor);

华清远见<嵌入式Linux应用开发班>培训教材2.菜单类

弹出式菜单QpopupMenu类以垂直列表的方式显示菜单项,它可以是单个的(例如上下文相关菜单),可以以菜单栏的方式出现,或者是别的弹出式菜单的子菜单出现。

每个菜单项可以有一个图标,一个复选框和一个加速器(快捷键),菜单项通常对应一个动作(例如存盘),分隔器通常显示成一条竖线,它用于把一组相关联的动作菜单分立成组。

下面是一个建立包含有New,Open和Exit菜单项的文件菜单的例子。

QPopupMenu *fileMenu = new QPopupMenu( this );

fileMenu->insertItem( "&New

fileMenu->insertItem( "&Open...

fileMenu->insertSeparator();

fileMenu->insertItem( "E&xit

当一个菜单项被选中,和它相关的插槽将被执行。加速器(快捷键)很少在一个没有键盘输入的设备上使用,Qt/Embedded的典型配置并未包含对加速器的支持。上面出现的代码“&New”意思是在桌面机器上以“New”的方式显示出来,但是在嵌入式设备中,它只会显示为“New”。

QmenuBar类实现了一个菜单栏,它会自动地设置几何尺寸并在它的父窗体的顶部显示出来,如果父窗体的宽度不够宽以至不能显示一个完整的菜单栏,那么菜单栏将会分为多行显示出来。Qt内置的布局管理能够自动调整菜单栏。

Qt的菜单系统是非常灵活的,菜单项可以被动态使能,失效,添加或者删除。通过子类化QcustomMenuItem,用户可以建立客户化外观和功能的菜单项。

3.工具栏

工具栏可以被移动到中心区域的顶部、底部、左边或右边。任何工具栏都可以拖拽到工具栏区域的外边,作为的浮动工具托盘。

QtoolButton类实现了具有一个图标,一个3D框架和一个可选标签的工具栏。切换型工具栏按钮具有可以打开或关闭某些特征。其他的则会执行一个命令。可以为活动、关闭、开启等模式,打开或关闭等状态提供不同的图标。如果只提供一个图标,Qt能根据可视化线索自动地辨别状态,例如将禁用的按钮变灰,工具栏按钮也能触发弹出式菜单。

QToolButton通常在QToolBar内并排出现。一个程序可含有任意数量的工具栏并且用户可以自由地移动它们。工具栏可以包括几乎所有部件,例如QComboBox和QSpinBox。

4.旁述

现在的应用主要使用旁述的方式去解释用户接口的用法。Qt提供了两种旁述的方式,即“提示栏”和“这是什么”帮助按钮。

•“提示栏”是小的,通常是黄色的矩形,当鼠标在窗体的某些位置游动时,它就会自动地出现。它主要用于解释工具栏按钮,特别是那些缺少文字标签说明的工具栏按钮的用途。下面就是如何设置一个“存盘”按钮的提示代码。

QToolTip::add(saveButton,"Save");

>培训教材当提示字符出现之后,还可以在状态栏显示更详细的文字说明。

对于一些没有鼠标的设备(例如那些使用触点输入的设备),就不会出现鼠标的光标在窗体上进行游动,这样就不能激活提示栏。对于这些设备也许就需要使用“这是什么”帮助按钮,或者使用一种姿态来表示输入设备正在进行游动,例如用按下或者握住的姿态来表示现在正在进行游动。

•“这是什么”帮助按钮和提示栏有些相似,只不过前者是要用户单击它才会显示旁述。在小屏幕设备上,要想单击“这是什么”帮助按钮,具体的方法是,在靠近应用的X窗口的关闭按钮“x”附近你会看到一个“?”符号的小按钮,这个按钮就是“这是什么”的帮助按钮。一般来说,“这是什么”帮助按钮按下后要显示的提示信息应该比提示栏要多一些。下面是设置一个存盘按钮的“这是什么”文本提示信息的方法:

QWhatsThis::add( saveButton, "Saves the current file." );

QToolTip和QWhatsThis类提供了可以通过重新实现来获取更多特殊化行为的虚函数,比如根据鼠标在部件的位置来显示不同的文本。

为了避免重复,使用QAction可保证菜单项的状态与工具栏保持同步,而工具提示能在需要的时候显示。禁用一个动作会禁用相应的菜单项和工具栏按钮。类似地,当用户单击切换型按钮时,相应的菜单项会因此被选中或不选。

12.2.6 Qt/Embedded对话框设计

Qt/Embedded对话框的设计比较复杂,要使用布局管理自动地设置窗体与别的窗体之间相对的尺寸和位置,这样可以确保对话框能够最好地利用屏幕上的可用空间,接着还要使用Qt图形设计器地可视化设计工具建立对话框。下面就详细讲解具体的步骤。

1.布局

Qt的布局管理用于组织管理一个父窗体区域内的子窗体。它的特点是可以自动设置子窗

华清远见<嵌入式Linux应用开发班>培训教材

体的位置和大小,并可确定出一个顶级窗体的最小和缺省的尺寸,当窗体的字体或内容变化后,它可以重置一个窗体的布局。

使用布局管理,开发者可以编写于屏幕大小和方向之外的程序,从而不需要浪费代码空间和重复编写代码。对于一些国际化的应用程序,使用布局管理,可以确保按钮和标签在不同的语言环境下有足够的空间显示文本,不会造成部分文字被剪掉。

布局管理提供部分用户接口组件,例如输入法和任务栏变得更容易。我们可以通过一个例子说明这一点,当Qtopia的用户输入文字时,输入法会占用一定的文字空间,应用程序这时也会根据可用屏幕尺寸的变化调整自己。

Qtopia的布局管理示例图如图12.11所示。

>培训教材

华清远见<嵌入式Linux 应用开发班>培训教材

• 设置一个最小尺寸,一个最大尺寸,或者为一些子部件设置固定的大小。

• 设置一些延伸项目或间隔项目,延伸或间隔项目会填充空余的布局空间。

• 改变子部件的尺寸策略。通过调用QWidget::setSizePolicy(),程序员可以仔细调整子部件的缩放行为。子部件可以设置为扩展、收缩、保持原大小等状态。

• 改变子部件的建议大小。QWidget::sizeHint()和QWidget::minimumSizeHint()会根据内容返回部件的首选尺寸和最小首选尺寸。内建部件提供了合适的重新实现。

• 设置延伸因子。延伸因子规定了子部件的相应增量,比如,2/3的可用空间分配给部件A 而三分之一分配给B 。

(2)布局嵌套

布局可以嵌

套任意层。图

12.13显示了一个对话框的两种大小。

可以看到,Qt 让布局变得非常容易。

通过子类化QLayout开发者可以定义自己的布局管理器。和Qt一起提供的customlayout 样例展示了三个自定义布局管理器:BorderLayout、CardLayout和SimpleFlow,程序员可以使用并修改它们。

Qt还包括QSplitter,是一个最终用户可以操纵的分离器。某些情况下,QSplitter可能比布局管理器更为可取。

为了完全控制,重新实现每个子部件的QWidget::resizeEvent()并调用QWidget::setGeometry(),就可以在一个部件中手动地实现布局。

2.Qt/Embedded图形设计器

Qt图形设计器是一个具有可视化用户接口的设计工具。Qt的应用程序可以完全用源代码来编写,或者使用Qt图形设计器来加速开发工作。启动Qt图形设计器的方法是:

cd qt-2.3.2/bin

./designer

这样就可以启动一个图形化的设计界面,如图12.14所示。

开发者单击工具栏上的代表不同功能的子窗体/组件的按钮,然后把它放到一个表单上,这样就可以把一个子窗体/组件放到表单上了。开发者可以使用属性对话框来设置子窗体的属性,精确地设置子窗体的位置和尺寸大小是没必要的。开发者可以选择一组窗体,然后对他们进行排列。例如,我们选定了一些按钮窗体,然后使用“水平排列(lay out horizontally)”选项对它们进行一个接一个的水平排列。这样做不仅使得设计工作变得更快,而且完成后的窗体将能够按照属性设置的比例填充窗口的可用尺寸范围。

图12.14 Qt图形设计器界面

>培训教材

华清远见<嵌入式Linux 应用开发班>培训教材

使用Qt 图形设计器进行图形用户接口的设计可以消除应用的编译、链接和运行时间,同时使修改图形用户接口的设计变得更容易。Qt 图形设计器的预览功能可以使开发者能够在开发阶段看到各种样式的图形用户界面,也包括客户样式的用户界面。通过Qt 集成功能强大的数据库类,Qt 图形设计器还可提供生动的数据库数据浏览和编辑操作。

开发者可以建立同时包含有对话框和主窗口的应用,其中主窗口可以放置菜单,工具栏,旁述帮助等的子窗口部件。Qt 图形设计器提供了几种表单模板,如果窗体会被多个不同的应用反复使用,那么开发者也可建立自己的表单模板以确保窗体的一致性。

Qt 图形设计器使用向导来帮助人们更快更方便地建立包含有工具栏、菜单和数据库等方面的应用。程序员可以建立自己的客户窗体,并把它集成到Qt 图形设计器中。

Qt 图形设计器设计的图形界面以扩展名为“ui ”的文件进行保存,这个文件有良好的可读性,这个文件可被uic (Qt 提供的用户接口编译工具)编译成为C++的头文件和源文件。Qmake 工具在它为工程生成的Makefile 文件中自动包含了uic 生成头文件和源文件的规则。

另一种可选的做法是在应用程序运行期间载入ui 文件,然后把它转变为具备原先全部功能的表单。这样开发者就可以在程序运行期间动态地修改应用的界面,而不需重新编译应用,另一方面,也使得应用的文件尺寸减小了。

3.建立对话框

Qt 为许多通用的任务提供了现成的包含了实用的静态函数的对话框类,主要有以下几种。

• QmessageBox 类:是一个用于向用户提供信息或是给用户进行一些简单选择(例如“yes ”或“no ”)的对话框类。如图12.15所示。

• progressDialog 类:包含了一个进度栏和一个“Cancel ”按钮。如图12.16所示。 •

Qwizard 类:提供了一个向导

对话框的框架。如图12.17所示。

1.实验目的

通过编写一个跳动的“Hello,World”字符串,进一步熟悉嵌入式Qt的开发过程。

2.实验步骤

(1)生成一个工程文件(.pro文件)

使用命令progen产生一个工程文件(progen程序可在tmake的安装路径下找到)。

如下所示:

progen –t app.t –o hello.pro

那样产生的hello.pro工程文件并不完整,开发者还需添加工程所包含的头文件,源文件等信息。

图12.18 Hello窗体的属性设置

>培训教材设置完成后,将其保存为hello.ui文件,这个文件就是Hello窗体的界面存储文件。

(3)生成Hello窗体类的头文件和实现文件

下面根据上述的界面文件hello.ui使用uic工具产生Hello窗体类的头文件和实现文件,具体方法是:

cd qt-2.3.7/bin

uic –o hello.h hello.ui

uic –o hello.cpp –impl hello.h hello.ui

这样就得到了Hello窗体类的头文件hello.h和实现文件hello.cpp。下面就可以根据需要实现的具体功能,在hello.cpp文件里添加相应的代码。

比如要在Hello的窗体上显示一个动态的字符串“Hello,World”,那么使用需要重新实现paintEvent(QPaintEvent *)方法,同时还需要添加一个定时器Qtimer实例,以周期性刷新屏幕,从而得到动画得效果。下面是修改后的hello.h和hello.cpp文件。

华清远见<嵌入式Linux应用开发班>培训教材

>培训教材

华清远见<嵌入式Linux应用开发班>培训教材

>培训教材

(4)编写主函数main()

一个Qt/Embeded应用程序应该包含一个主函数,主函数所在的文件名是main.cpp。主函数是应用程序执行的入口点。以下是“Hello,World”例子的主函数文件main.cpp的实现代码:

/**************************************************************************** ** 以下是main.cpp 源代码

华清远见<嵌入式Linux应用开发班>培训教材

(6)生成Makefile文件

编译器是根据Makefile文件内容来进行编译的,所以需要生成Makefile文件。Qt提供的tmake工具可以帮助我们从一个工程文件(.pro文件)中产生Makefile文件。结合当前例子,要从hello.pro生成一个Makefile文件的做法是首先查看环境变量$TMAKEPA TH是否指向arm 编译器的配置目录,在命令行下输入以下命令:

echo $TMAKEPATH

如果返回的结果末尾不是…/qws/linux-arm-g++的字符串,那您需要把环境变量$TMAKEPATH所指的目录设置为指向arm编译器的配置目录,过程如下,

>培训教材export TMAKEPATH = /tmake 安装路径/qws/linux-arm-g++

同时,应确保当前的QTDIR环境变量指向Qt/Embedded的安装路径,如果不是,则需要执行以下过程。

export QTDIR = ……/qt-2.3.7

上述步骤完成后,就可以使用tmake生成Makefile文件,具体做法是在命令行输入以下命令:tmake –o Makefile hello.pro

这样就可以看到当前目录下新生成了一个名为Makefile的文件。下一步,需要打开这个文件,做一些小的修改。

1)将LINK = arm-linux-gcc这句话改为:

LINK = arm-linux-g++

这样做是因为要是用arm-linux-g++进行链接。

2)将LIBS = $(SUBLIBS) -L$(QTDIR)/lib -lm –lqte这句话改为:

LIBS = $(SUBLIBS) -L/usr/local/arm/2.95.3/lib -L$(QTDIR)/lib -lm –lqte

这是因为链接时要用到交叉编译工具toolchain的库。

(7)编译链接整个工程

最后就可以在命令行下输入make命令对整个工程进行编译链接了。

make

make生成的二进制文件hello就是可以在FS2410上运行的可执行文件。

本章小结

本章主要讲解了嵌入式Linux的图形编程。首先介绍了几种常见的嵌入式图形界面编程机制,并给出了它们之间的相互关系。

接下来,本章介绍了Qt/Embedded了开发入门,包括环境的搭建、信号与插槽的概念与应用以及图形设计器的应用。

本章的实验介绍了如何使用Qt编写“Hello,World”小程序,从中可以了解到Qt编程过程的全过程。

华清远见<嵌入式Linux应用开发班>培训教材

文档

第12章Qt图形编程

“黑色经典”系列之《嵌入式Linux应用程序开发详解》Linux设备驱动程序的基本功能常见设备驱动接口函数掌握键盘设备驱动程序编写步骤华清远见培训教材12.1嵌入式GUI简介目前的桌面机操作系统大多有着美观、操作方便、功能齐全的GUI(图形用户界面),例如KDE或者GNOME。GUI(图形用户界面)是指计算机与其使用者之间的对话接口,可以说,GUI是当今计算机技术的重大成就。它的存在为使用者提供了友好便利的界面,并大大地方便了非专业用户的使用,使得人们从繁琐的命令中解脱出来,可以通过窗口、菜单
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top