admin 管理员组

文章数量: 1184232


2024年3月13日发(作者:merge函数用法python)

1 Qt4界面开发

1.1 Qt历史

Qt是一个用于桌面系统和嵌入式开发的跨平台应用程序框架。它包括一个直观的API

和一个丰富的类库,以及用于GUI开发和国际化的集成工具,另外它支持Java™和C++

开发。Qt让企业无须重新编写源代码,便可以构建运行在不同桌面操作系统和嵌入式设备

上的软件应用程序。

Qt框架最早可公开获取是在1995年5月。最初是由Haavard Nord(TrollTech公司

的首席执行官)和Eirik Chambe-Eng(TrollTech公司的董事会主席)。Haavard和Eirik

最早在特隆赫姆的挪威技术学院相遇,在那里他们双双获得了计算机科学硕士学位。

早在1991年,Haavard 就开始写一些最终成为Qt的类,并和 Eirik合力设计。在接

下来的一年,Eirik提出了“信号和槽”的思想,一个现在已经被一些其他套装工具包含简单

但功能强大的GUI编程范式。Haavard 接受了这一思想并手工生成了这一思想的代码实

现。到1993年,Haavard和Eirik已经完成了Qt的第一个图形内核的开发并能用它来实

现一些他们所需的物件。在这一年的年末,Haavard建议他们一起去经商,创建一个“世

上最好的C++ GUI框架”。

字母“Q”被选为类的前缀是因为这个字母在Haavard的Emacs字体中看起来很漂

亮。受到Xt(the X toolkit)的启发,字母“t”被追加来表示“toolkit”。公司在1994年5

月4日成立,起初被命名为“Quasar Technologies”,之后被改名为“Troll Tech”,今天则

被称为奇趣科技(Trolltech)。

1995年5月20日,Qt 0.90被上传到。六天后,这一发布在

ce被宣布。这是Qt的第一个公共发行版。Qt可以被用在Windows

和Unix开发中,在两个系统中提供相同的API。Qt从一开始就可以在两种许可协议下获取:

一个是商业开发中需要的商业许可协议,一个用于开源开发的自由软件版。

1996年3月,欧洲航天局成为Qt的第一个客户,一下买了十个Qt商业许可。Qt 0.97

在同年的5月底发布,1996年9月24日,Qt 1.0发布。到了同年年底,Qt到达了版本1.1;

拥有8个客户,每一个都在不同的国家,他们购买了18个商业许可。

Qt 1.2 在1997年4月发布。Matthias Ettrich利用Qt构建KDE的决定帮助Qt成为

Linux C++ GUI 开发的实际标准,1997年9月Qt 1.3发布。

1998年9月,Qt 1的最后一个主要发行版1.40发布。Qt 2.0于1999年7月发布。

Qt 2有了一个新的开源许可协议,发布许可协议(QPL),遵守开源的定义。1999年8月,

Qt赢得了LinuxWorld的“最佳开发库/工具”大奖。

2000年奇趣科技发布了Qtopia核心(后来成为Qt/Embedded)。它被设计用来运行

在嵌入式Linux设备上并提供了自己的窗口系统作为X11的一个轻量级代替。现在Qt/X11

和Qtopia核心都可以通过GNU通用许可(GPL)获取。到2000年年底,奇趣科技成立了

Trolltech Inc.(USA)并且发布了Qtopia的第一个版本,一个移动电话和PDAs应用程序平

台。Qtopia赢得了2001和2002年LinuxWorld的“最佳嵌入式 Linux 解决方案”大奖,

1

Qtopia Phone 也在2004年赢得了相同的荣誉。

2001年Qt 3.0发布。Qt现在可以在Windows,Mac OS X,Unix和Linux(桌面和嵌

入式系统)上获取。Qt 3新增了42个类,代码超过了500,000行。Qt3是Qt2的一个大的

进步,包括相当大的本地化和Unicode支持,一个全新的文本查看和编辑物件,和一个类

似Perl的正则表达式类。2002年Qt 3赢得了软件开发时代的“Jolt 产品大奖”。

2005年夏天,Qt 4.0发布。包括大约500个类和9000多个函数,Qt 4比以前的任何

版本都要大,都要优雅,并且它已经被分割成几个库,因此程序员只需要包含他们需要的Qt

的一部分。Qt 4包含了一套全新的高效且易用的模版容器,高级的模型/视图函数,一个快

速且有弹性的2D绘图框架,和功能强大的Unicode文本查看/编辑类,还有一些未提到的

针对所有类的许多得较小的增强,这较以前的版本有了巨大的进步。Qt 4是第一个在所有

支持平台上都可以通过商业和开源开发许可获得的Qt版本。

从奇趣诞生的第一天,Qt的流行就从未减弱过,即使今天也仍在继续。这一成功不但

反映了Qt良好的品质,也反映了Qt的使用乐趣。在最近的十年中Qt从默默无闻成长为

一个全世界成千上万客户和开源开发者每天都要使用的产品。

1.2 Qt产品概述

Qt 是一个全面的开发框架。它包含一个广泛的队列,该队列为功能、性能和工具队列,

用以确保针对多客户端和服务器端的高性能、跨平台开发。针对范围广泛的各行各业,包括

Google™、Adobe Lucasfilm 和 Skype™,通过在Qt一个平台上的软件投资而涵盖其它众多

平台,Qt可以缩短投入市场的时间并且提高生产效率。

图1.1 Qt框架结构图

z Qt类库模块是一个拥有超过400个类,同时不断扩展的类库。它封装了用于端到

端应用程序开发所需要的所有基础结构。

2

z Qt设计者(Designer)是一个功能强大的GUI布局与窗体构造器,能够在所有支

持的平台上,以本地化的视图外观与认知,快速开发高性能的用户界面。

z Qt语言家(Linguist)是一套用来消除国际化工作流程中所带来障碍的工具。

z Qt助手(Assisstant)一个完全可自定义,重新分配的帮助文件或文档浏览器,它

可与基于Qt 的应用程序运行。

z Java程序员可获得的Qt Jambi作为一个支持Java™的跨平台多用户端应用开

发框架,Qt现已提供给Java程序员。

Qt拥有一系列窗体(在 Windows 术语中称为“控件”),这些窗体可提供标准的GUI

功能。Qt引入了一种名为“信号和槽”的新型替代技术,供对象之间通信使用,它取代了

在过时的框架中使用的老旧的、缺乏安全性的传统回调技术。另外,Qt还提供了一种传统

事件模型,用来处理鼠标单击、按键以及其他用户输入操作。Qt的跨平台GUI应用程序可

以支持现代应用程序所需的所有用户界面功能,例如:菜单、上下文菜单、拖放以及可停靠

工具栏。使用Qt提供的桌面集成功能,通过利用每个平台提供的服务,可以将应用程序扩

展至所在的桌面环境中。

Qt还提供了一款专门用于用户界面图形设计的工具--Qt Designer。Qt Designer

除了提供绝对定位功能以外,还支持强大的布局功能。使用Qt Designer,既可专门设计

GUI,又可以利用它提供的与流行的集成开发环境集成的功能,用其开发整个应用程序。

Qt对2D和3D图形有着卓越的支持。Qt实际上是针对平台独立的OpenGL编程而

开发的标准GUI框架。Qt 4的绘图系统为所有支持的平台提供了高质量的渲染功能。使用

Qt 4的高级画布框架,开发人员可以创建各种交互式图形应用程序,从而充分利用Qt的先

进绘图功能。

Qt可以使用标准数据库创建与平台无关的数据库应用程序。针对Oracle、Microsoft

SQL Server、Sybase Adaptive Server、IBM DB2、PostgreSQL.、MySQL、Borland

Interbase、SQLite 和 ODBC 兼容的数据库,Qt提供了本地驱动。另外,Qt还提供了专

用于数据库的控件,使任何内建或自定义控件均可感知数据。

使用Qt的样式支持和主题支持功能,Qt编程可获得所有支持的平台的本地化观感。

从单一源码树只需采用重新编译方式即可为Windows 98至Windows XP和Windows

VistaTM、Mac OS X、Linux、Solaris、HP-UX 以及其他使用X11的Unix版本生成应用程

序。另外,Qt应用程序经过编译也能在Qtopia中运行。使用Qt的qmake构建工具,可

为目标平台生成相应的makefile或.dsp文件。

由于Qt的架构充分利用了底层平台的优点,许多用户在Windows,Mac OS X和Unix

平台上做单一平台开发时也使用Qt,因为他们更愿意使用Qt的方法。Qt包含了对具体平

台的特有功能的支持,例如:Windows中的ActiveX以及Unix中的Motif。

Qt全面使用 UnicodeTM,并且对国际化支持十分成熟。Qt还为翻译人员提供了Qt

Linguist(语言家)以及其他工具。应用程序可以轻松地混合使用阿拉伯语、汉语、英语、

以色列语、日语、俄罗斯语以及Unicode支持的其他语言。

Qt提供了一系列与特定域相关的类。例如,Qt的XML模块提供了SAX和DOM类,

可以读取并操作以XML格式存储的数据;使用Qt的STL兼容集合类,可以将对象存储在

内存中;使用与Java和C++标准模板库(STL)中相同样式的迭代器来操作对象;使用Qt

的输入/输出和网络连接类,可以使用标准协议处理本地文件和远程文件。

3

插件和动态库可以进一步扩展Qt应用程序的功能。插件提供了附加编解码器、数据库

驱动、图像格式、样式和控件。

QtScript模块通过提供Qt Script以支持应用程序的脚本化,Qt Script是基于ECMA

脚本的类似于JavaScript的语言。此技术允许开发者向用户提供对应用程序的一部分的有

限访问,以用于脚本化用途。

Qt是一种成熟的C++框架,在全球各地广泛使用。Qt除了具有众多商业用途以外,

其开源版本还为KDE(即:Linux 桌面环境)奠定了基础。Qt跨平台的构建系统、可视化

窗体设计以及一流的API,使应用程序开发成为一种乐趣。

1.3 Windows XP下安装Qt

1)下载安装文件

首先去官方网站下载Qt OpenSource(),现在

的最新版本是4.4,下载连接:

/developer/downloads/qt/windows。

官方网站申明Qt OpenSource版本只支持MinGW编译器,所以在安装QT之前最好先

安装MinGW。不事先安装也可以,QT安装时会让你指定MinGW的安装位置,如果未安装,

则QT的安装程序会引导你进行MinGW的网络安装。不过,还是建议不要使用这种方式,

因为网络安装MinGW的速度比较慢,不支持断点续传。

下载MinGW的安装程序,使用官方网站/提供的安装文件

或更高版本。

2)安装MinGW

图 1.2 安装MinGW

4

图 1.3 选择安装包

图 1.4 选择需要安装的编译器

5

图 1.5 选择安装路径

图 1.6 安装完成

3)安装Qt4.4

6

图 1.7 安装Qt

图 1.8 选择组件

7

图 1.9 选择安装路径

图 1.10 选择已安装MinGW的路径

8

图 1.11 Qt4.4安装完成

4)编译QT的Debug库

到这里,安装工作还没有完全搞定,一般都会存在两个问题:

1、把代码拿到QT安装目录之外编译,总报错,错误信息是

“QtValidLicenseForGuiModule' does not name a type”。如果把代码放到QT安装目

录内,则编译正常。

2、无法用Debug方式编译代码,原因是安装文件里面没带QT的Debug库。不能编

译Debug程序会给以后的调试工作带来许多不便。

以上的两个问题,解决的方法是运行[开始]>[程序]>[Qt by Trolltech v4.0.1

(OpenSource)]>[Qt 4.0.1 (Build Debug Libraries)],[Qt 4.0.1 (Build Debug

Libraries)],运行QT安装目录下的“ compile_debug”。该命令有两个作

用,一是重新编译生成qmake程序,二是编译生成了QT的Debug库。此时,你可以去

查看一下QT安装目录下的lib目录,.a文件会多了一些以字母d结尾的库文件,这些就是

QT的Debug库。

5)Hello world程序

编译一个最简单的Hello world程序,验证QT和MinGW安装无误。

QT安装目录里已经有Hello world程序的源码,在QT安装目录的

examplestutorialstutorialt1中,以命令行方式进入该目录,分别运行“qmake”命

令和“make”命令,即可在release目录中生成Hello world的可执行程序,若运行“make

debug”命令,则会在debug目录中以Debug编译方式生成Hello world的可执行程序。

9

图 1.12 Hello world程序

1.4 Qt开发社区

全球各大公司以及独立开发人员每天都在加入Qt的开发社区。他们已经认识到了Qt

的架构本身便可加快应用程序开发进度。这些开发人员,无论是想开发单平台软件、还是想

开发跨平台软件,都可从Qt统一而直接的API、强大的构建系统以及各种支持工具(例如

Qt Designer)中受益无穷。

Qt具有一个极具活力并十分有益的用户社区,用户可以通过以下方式进行沟通:

qt-interest邮件列表、Qt Centre 网站(网址为:)以及其他社区网

站和博客。另外,许多Qt开发人员也是KDE社区的活跃成员。如今,Qt的用户社区还提

供了越来越多的第三方商业软件和开源软件;有关最新信息,请访问 。

Qt 的一系列文档可在线访问,网址为:。另外,有关 Qt 编程 的

详细介绍,市场上还有一系列英语、法语、德语、俄语、日语以及中文版本书籍。Qt的官

方书籍是《C++ GUI Programming with Qt 4》(ISBN 0-13-187249-4)。

除了为C++开发人员提供综合框架以外,Qt还可以使用其他语言编程。Qt本身包含

了QtScript模块,这是一种类似JavaScript的技术,使用这一技术,开发人员可以用编写

脚本的方法让用户访问应用程序的某些特定区域。

奇趣科技公司还提供了Qt Jambi 这一技术,使用这种技术,Java 开发人员可以基

于 Java 编程语言来使用Qt。

另外,奇趣科技公司及第三方公司针对 JavaScript、Python、Perl 和 Ruby 提供了

语言绑定;其中许多解决方案都是由开源开发团队提供并加以维护的。

1.5 窗体

Qt提供了一系列标准窗体,使用这些部件,可以为应用程序创建图形用户界面。Qt

的窗体灵活易用,可以进一步派生子类,以满足特殊需求。

窗体是指组合在一起创建用户界面的可视元素。按钮、菜单、滚动条、消息框以及应用

程序窗口都是窗体的例子。Qt的窗体并没有在“控件”或“容器”之间加以截然区分。所

有窗体既可以作为控件使用、又可以作为容器使用。通过从现有Qt窗体派生子类或者从头

开始新建窗体(如有必要),则可轻松创建自定义的窗体。

标准窗体是由QWidget类及其子类提供的,而自定义窗体则可通过从标准窗体派生子

类并重写虚函数的方式来创建。

窗体可以包含任意数量的子窗体。子窗体位于父窗体区域内。不含父窗体的则称为顶层

窗体(“窗口”),这类窗体通常在桌面环境的任务栏中有自己的启动入口。Qt对窗体没有任

何硬性限制。任何一个窗体都可以成为顶层窗体;同时任何一个窗体也可以成为其他窗体的

子部件。使用布局管理器可以自动设置子窗体在父区域内的位置,如有必要,也可以手动设

置。禁用、隐藏或删除父窗体时,也同样会递归地禁用、隐藏或删除其所有子窗体。

10

标签、消息框、工具提示以及其他文本窗体并不限定于某一种色彩、字体和语言。Qt

的文本着色窗体使用HTML的子集,可以显示丰富的多语言文本,同时大多数控件可以用一

种描述性语言控制风格。

1.5.1 内建窗体

图1.13展示了不同用户界面组件中所选择使用的Qt窗体。这些窗体使用Qt Designer来布

局,使用Plastique样式来着色,展示了Qt 4在Linux中的标准外观。

图1.13所示窗体包括标准输入控件,例如:QLineEdit用来输入一行文本;QCheckBox用

来启用/禁用简单的独立设置;QSpinBox和QSlider用来指定数量;QRadioButton用来启

用/禁用互斥的设置;QComboBox表示单击时,将打开显示选择菜单。可点击的按钮则由

QPushButton提供。

另外,

图1.13中还显示了容器窗体,例如QTabWidget和QGroupBox。这些窗体是专

门由Qt Designer管理的,可以帮助设计人员快速创建并维护新用户界面。与用户界面设计

人员相比,开发人员更倾向于经常使用比较复杂的窗体(例如,图

1.13“Create Poster”

对话框中显示的QScrollArea),其原因是这些复杂窗体可以用来显示专业化内容或动态内

容。

Qt提供的窗体远远不止此处所列出的这些。Qt的在线Widget Gallery中还提供了许

多可用的窗体以及指向其类文档的链接。

图1.13 使用不同控件创建的对话框

11

图1.14 Qt 提供了一系列标准窗体

也可轻松使用手动方式编写用户界面。可以使用以下代码来创建“Find Text”对话框图

1.13

的选项组框。

QGroupBox *optionsGroupBox = new QGroupBox(tr("Options"));

QCheckBox *caseCheckBox = new QCheckBox(tr("C&ase sensitive"));

QCheckBox *directCheckBox = new QCheckBox(tr("Search fo&rwards"));

QCheckBox *wordsCheckBox = new QCheckBox(tr("Whole &words"));

QCheckBox *startCheckBox = new QCheckBox(tr("From &start of text"));

QGridLayout *optionsLayout = new QGridLayout;

optionsLayout->addWidget(caseCheckBox, 0, 0);

optionsLayout->addWidget(wordsCheckBox, 0, 1);

optionsLayout->addWidget(directCheckBox, 1, 0);

optionsLayout->addWidget(startCheckBox, 1, 1);

optionsGroupBox->setLayout(optionsLayout);

12

1.5.2 定制窗体

通过从QWidget及其派生类派生子类,开发人员可以创建自己的窗体和对话框。为了

举例说明派生子类的步骤,我们从Qt 4示例目录中列出了模拟时钟窗体的完整代码,该部

件可以显示当前时间并自动更新。

AnalogClock 窗体在analogclock.h文件中定义:

#include

class AnalogClock : public QWidget

{

Q_OBJECT

public:

AnalogClock(QWidget *parent = 0);

protected:

void paintEvent(QPaintEvent *event);

};

该窗体继承通用的QWidget类,其构造函数是典型的窗体类的构造函数形式,带有一

个可选的parent参数。paintEvent()函数从QWidget继承而来,此函数在任何窗体需要

更新时被调用。

AnalogClock 类的实现在文件中:

#include

#include "analogclock.h"

AnalogClock::AnalogClock(QWidget *parent)

: QWidget(parent)

{

QTimer *timer = new QTimer(this);

connect(timer, SIGNAL(timeout()), this, SLOT(update()));

timer->start(1000);

setWindowTitle(tr("Analog Clock"));

resize(200, 200);

}

构造函数设置了一个定时器,给窗口设置了一个标题,并确保窗口默认大小正确合理。

计时器的配置设置为每1000毫秒发送一次信号。启动计时器之前,系统使用Qt的信号和

槽机制将此计时器连接至窗体的update()功能,从而确保时钟显示最新时间。

每次调用时,paintEvent()函数都会简单地将整个窗体重新绘制一次。它使用Qt的绘

13

图系统绘制钟表盘和时针分针。

void AnalogClock::paintEvent(QPaintEvent *)

{

static const QPoint hourHand[3] = {

QPoint(7, 8),

QPoint(-7, 8),

QPoint(0, -40)

};

static const QPoint minuteHand[3] = {

QPoint(7, 8),

QPoint(-7, 8),

QPoint(0, -70)

};

QColor hourColor(127, 0, 127);

QColor minuteColor(0, 127, 127);

int side = qMin(width(), height());

QTime time = QTime::currentTime();

该函数首先以窗体的最短边作为时钟尺寸,设置简单主体信息及色彩信息。然后在窗体

的中央绘制钟表盘,并使用反锯齿(如果可用)在正确位置上绘制时针和分针。

QPainter painter(this);

derHint(QPainter::Antialiasing);

ate(width() / 2, height() / 2);

(side / 200.0, side / 200.0);

(Qt::NoPen);

sh(hourColor);

();

(30.0 * ((() + () / 60.0)));

nvexPolygon(hourHand, 3);

e();

14

(hourColor);

for (int i = 0; i < 12; ++i) {

ne(88, 0, 96, 0);

(30.0);

}

(Qt::NoPen);

sh(minuteColor);

();

(6.0 * (() + () / 60.0));

nvexPolygon(minuteHand, 3);

e();

(minuteColor);

for (int j = 0; j < 60; ++j) {

if ((j % 5) != 0)

ne(92, 0, 96, 0);

(6.0);

}

图1.15模拟时钟示例

在此示例中,main()函数是最基本的功能。它仅仅设置了一个应用程序对象,构建并

15

显示了时钟窗体。最后,需要启动应用程序的事件循环,以便 Qt 可以开始处理事件:

#include

#include "analogclock.h"

int main(int argc, char *argv[])

{

QApplication app(argc, argv);

AnalogClock clock;

();

return ();

}

此示例程序只包含一个顶层时钟窗体,没有任何子窗体。若要构建复杂的窗体,则需将

多个窗体组合在不同布局中。

1.6 信号和槽

信号和槽为对象之间的通信提供了便利条件。它们易于理解和使用,并受到Qt

Designer的全面支持。

GUI应用程序要对用户操作做出响应。例如,当用户单击菜单项目或者工具栏按钮时,

GUI应用程序便会执行某段代码。实际上,我们更希望任何一类对象均可彼此互相通信。编

程人员必须将事件与相关代码相关联。老的开发工具套件(Toolkit)使用的机制不是类型安

全(type-safe)的(例如,容易引起崩溃),缺乏灵活性而且不是面向对象的。

奇趣科技公司创造了一种名为“信号和槽”的解决方案。信号和槽机制是一种功能强大

的对象间通信机制,完全可以取代老旧的开发套件所使用的粗糙的回调和消息映射。信号和

槽机制极为灵活,完全面向对象,并且使用 C++ 来实现。

使用原有回调机制,若要将某一代码与按钮关联在一起,必须将函数指针传输给该按钮。

单击此按钮时,系统将调用此函数。而对于老的工具套件而言,调用此函数时,它不确保将

正确类型的参数传递给该函数,这样很有可能导致崩溃。回调方法的另一问题是:它将GUI

元素与功能紧紧地捆绑在一起,这样导致很难独立开发类。

而Qt的信号和槽机制则不同。发生事件时,Qt窗体将会发出信号。例如,单击某一

按钮时,该按钮将发出“clicked”信号。编程人员要想连接一个信号可以创建一个函数(即

“槽”)、并调用connect()函数将信号与槽关联起来。Qt的信号和槽机制不要求各类彼此

感知,这样可以更轻松地开发极易重新使用的类。由于信号和槽都属于类型安全的,因此,

类型错误都将报告为警告,因此不会发生崩溃。

例如,如果“退出”按钮的clicked()信号与应用程序的quit()槽相连,那么如果用户

单击“退出”,则会终止该应用程序。如果以代码形式表示,则应将上述过程编写为:

connect(button, SIGNAL(clicked()), qApp, SLOT(quit()));

在执行Qt应用程序的过程中,可以随时添加或移除连接。可将连接设置为在发出信号

时执行,或者排队稍后执行,可以在不同的线程的对象之间建立连接。

16

信号和槽通过平滑的扩展C++语法并充分利用C++的面向对象特性实现。信号和槽是

类型安全的,可以重载,也可以重新实现,可以出现在类的公有区、保护区或私有区。若要

使用信号和槽,必须继承QObject或其子类,并在类的定义中包括Q_OBJECT宏。信号

在类的“信号区”声明,而槽则是在“公有槽区”、“保护槽区”或“私有槽区”中声明的。

1.6.1 信号和槽示例

以下是 QObject 子类的示例:

class BankAccount : public QObject

{

Q_OBJECT

public:

BankAccount() { curBalance = 0; }

int balance() const { return curBalance; }

public slots:

void setBalance(int newBalance);

signals:

void balanceChanged(int newBalance);

private:

int currentBalance;

};

与多数C++ 类的风格类似,BankAccount类拥有构造函数、balance()“读取”函

数和 setBalance()“设置”函数。它还拥有balanceChanged()信号,帐户余额更改时

将发出此信号。发出信号时,与它相连的槽将被执行。

Set函数是在公共槽区中声明的,因此它是一个槽。槽既可以作为成员函数,与其他任

何函数一样调用,也可以与信号相连。以下是setBalance()槽的实现过程:

void BankAccount::setBalance(int newBalance)

{

if (newBalance != currentBalance) {

currentBalance = newBalance;

emit balanceChanged(currentBalance);

}

}

语句emit balanceChanged(currentBalance); 将发出balanceChanged()信

17

号,并使用当前新余额作为其参数。

关键字emit类似于“signals”和“slots”,由Qt提供,并由C++预处理器转换成标

准C++ 语句。

以下示例说明如何连接两个BankAccount对象:

BankAccount x, y;

connect(&x, SIGNAL(balanceChanged(int)), &y, SLOT(setBalance(int)));

ance(2450);

当x中的余额设置为2450时,系统将发出balanceChanged()信号。y中的

setBalance()槽收到此信号后,将y中的余额设置为2450。一个对象的信号可以与多个不

同槽相连,多个信号也可以与特定对象中的某一个槽相连。参数类型相同的信号和槽可以互

相连接。槽的参数个数可以少于信号的参数个数,这时多余的参数将被忽略。

图 1.16信号和槽连接的示例

1.6.2 元对象编译器

信号和槽机制是采用标准C++来实现的。该实现使用C++预处理器和Qt所包括的

moc(即:元对象编译器)。元对象编译器读取应用程序的头文件,并生成必要的代码,以

支持信号和槽机制。qmake生成的Makefiles将自动调用元对象编译器。开发人员无需编

辑、甚至无需查看生成的代码。

除了处理信号和槽以外,元对象编译器还支持Qt的翻译机制、属性系统及其扩展的运

行时类型信息。它还使C++程序进行运行时自检成为可能,并可在所有支持的平台上工作。

1.7 GUI 应用程序

使用Qt可以轻松快速地构建流行的GUI应用程序,通过手工编码或使用Qt的可视设

计工具Qt Designer即可完成。

Qt提供了创建现代GUI应用程序所需的所有类和函数。使用Qt,可以创建“主窗口”

样式的应用程序(其中心区域周围含有菜单栏、工具栏以及状态栏)和“对话框”样式的应

用程序(这些应用程序使用按钮或选项卡来显示选项和信息)。Qt既支持SDI(单一文档界

18

面)、又支持MDI(多文档界面)。Qt还持拖放操作以及剪贴板。图 1.17显示了一个应用程

序主窗口和TextEdit控件,该主窗口中包含主菜单、工具栏和围绕着中心窗体的停靠窗口。

图 1.17 Qt 4 主窗口示例

工具栏可以在工具栏区域内移动,也可以拖到其他区域,还可以作为工具板浮动。此功

能为内建功能,无需任何附加代码。当然,如有需要,编程人员可以对工具栏的行为加以限

制。

Qt使编程变得更简易。例如,如果某一菜单选项、工具栏按钮以及键盘快捷键都执行

同一操作,那么只需为该操作编写一次代码。

Qt还支持消息框、向导页和所有标准对话框,这样方便应用程序向用户提出问题,并

让用户选择文件、文件夹、字体和色彩。实际上,若要显示消息框或标准对话框,则只需编

写一行语句,该语句使用Qt某一静态函数即可。

使用系统注册表或文本文件,Qt可以采用与平台无关的方式存储应用程序的设置,从

而记录项目(例如,用户首选项、最近使用的文件、窗口以及工具栏位置和大小),供稍后

使用。

Qt通过一组代表通用构造方式的类支持多线程编程,这样Qt的程序可以充分利用多

线程来执行计算、耗时任务或加快响应速度。应用程序也可使用Qt的桌面集成功能与用户

桌面环境提供的服务进行交互。

1.7.1 主窗口

QMainWindow类为典型应用程序的主窗口提供了一个框架。主窗口包含一系列标准

控件。主窗口的顶部是一个菜单栏,菜单栏下面是工具栏,整个工具栏区域位于窗口顶部、

左侧、右侧以及底部。状态栏则位于底部工具栏区域下的主窗口区域中。工具提示和“这是

什么?”帮助为用户界面元素提供了气球帮助。

对于SDI应用程序,QMainWindow的中心区域可以包含任何窗体。例如,文本编辑

器可以使用QTextEdit作为中心窗体:

QTextEdit *editor = new QTextEdit(mainWindow);

mainWindow->setCentralWidget(editor);

19

对于MDI应用程序,中心区域通常放置 一个QMdiArea窗体,并包含若干

QMdiSubWindow窗体。

1.7.2 菜单

QMenu窗体以垂直列表的方式向用户展示菜单项目。菜单既可以单独显示(例如,上

下文弹出菜单)、可以显示在菜单栏上、也可以成为另一弹出菜单的子菜单。菜单可以具有

tear-off handle。

每个菜单项目都可拥有图标、复选框和快捷键。通常,菜单项目与动作相对应(例如,

“保存”)。分隔符项显示为一条横线,可以用来将相关动作采用可视方式集中在一起。下面

我们举例说明如何创建带有“新建”、“打开”和“退出”菜单项目的“文件”菜单:

QMenu *fileMenu = new QMenu(this);

fileMenu->addAction(tr("&New"), this, SLOT(newFile()), tr("Ctrl+N");

fileMenu->addAction(tr("&"), this, SLOT(open()), tr("Ctrl+O"));

fileMenu->addSeparator();

fileMenu->addAction(tr("E&xit"), qApp, SLOT(quit()), tr("Ctrl+Q"));

选中菜单项目时,系统将执行对应的槽。请注意:在此情况下,tr()函数将采用用户的

本地语言来获取菜单文本。

QMenuBar类实现了菜单栏。菜单栏会自动位于父窗体(通常是指QMainWindow)

的顶部,如果父窗口不够宽,则其内容将分为几行排列。Qt的布局管理器可以管理任何菜

单栏。在Macintosh系统中,菜单栏出现在屏幕顶部。下面我们举例说明如何创建带有“文

件”、“编辑”和“帮助”菜单的菜单栏:

QMenuBar *menuBar = new QMenuBar(this);

menuBar->addMenu(tr("&File"), fileMenu);

menuBar->addMenu(tr("&Edit"), editMenu);

menuBar->addMenu(tr("&Help"), helpMenu);

Qt的菜单十分灵活,是整个集成“动作”系统(action system)的一个组成部分。您可

启用或禁用任何动作,也可将操作动态添加至菜单中,稍后再移除该动作。

1.7.3 工具栏

工具栏包含各种按钮以及用户执行操作相关的其他控件。可以随意在主窗口中央区域的

顶部、左侧、右侧以及底部移动工具栏。任何工具栏均可从工具栏区域中拖出,并可作为独

立的工具板浮动。

QToolButton 类实现了带有图标、不同风格的边框以及可选文字标签的工具栏按钮。

切换(toggle)工具栏按钮负责开关功能,其他工具栏按钮则负责执行命令。活动模式、

禁用模式、启用模式以及开/关状态均使用不同图标表示。如果只有一个图标,那么Qt将

20

使用可视标记(例如,以灰色显示禁用的按钮)自动区分上述状态。工具栏按钮还可触发弹

出菜单。

通常,工具栏按钮并列排在工具栏区域内。一个应用程序可以拥有任意数量的工具栏,

用户可以在四周自由移动工具栏,或将其彻底拆离主窗口。工具栏几乎可以包含任意控件类

型;例如常用的QComboBox和QSpinBox控件。

图 1.18 Mac OS X系统上支持的统一工具栏

1.7.4 动作

若要执行某一特定动作,应用程序通常向用户提供了几种不同的执行方式。例如,大多

数应用程序经常会提供以下几种方式:从“文件”菜单中调用“保存”动作、从工具栏(工

具栏中的软盘形状按钮)以及快捷键(Ctrl+S)。QAction类负责封装此概念。它支持编程人

员在单一位置定义动作。

以下代码使用菜单项目、工具栏按钮以及键盘快捷键来实现“保存”动作,所有这些方

式都可以使用工具提示和“这是什么?”信息提供交互式帮助。

QAction *saveAct = new QAction(tr("Save"), saveIcon, tr("&Save"),

tr("Ctrl+S"),this);

connect(saveAct, SIGNAL(activated()), this, SLOT(save()));

saveAct->setWhatsThis(tr("Saves the current file."));

saveAct->addTo(fileMenu);

saveAct->addTo(toolbar);

为了避免重复劳动,可以使用QAction确保菜单项目的状态与相关工具栏按钮的状态

保持同步,还可确保在必要时显示交互式帮助。禁用某一动作将意味着禁用任何对应的菜单

项目和工具栏按钮。同样,如果用户单击工具栏中的切换(toggle)按钮,那么也会切换

对应的菜单项目。

1.7.5 停靠窗口

停靠窗口是指用户可以在工具栏区域内或区域间随意移动的窗口。用户可以对停靠窗口

解锁,使该窗口浮在应用程序顶部,也可以使窗口最小化。停靠窗口是由QDockWidget

类提供的。通过QDockWidget实例化并添加窗体,可以创建自定义停靠窗口。如果停靠

窗口占据水平区域(例如:在主窗口的顶部),那么窗体将会横向排列;如果占据垂直区域

(例如,在主窗口的左侧),那么窗体将会纵向排列。停靠区域可嵌套,以允许停靠窗口堆

叠为多行或多列。

21

图 1.19 停靠区域示例

主窗口上的窗体停靠把手能显示动画,反馈给用户该窗体可停靠的应用程序的什么位

置。这些动画默认即使能,但可根据需要去除。

停靠窗口可显示垂直的标题栏,窗口之前还可共享区域—当发生区域共享时,停靠窗口

将容纳在标签页中。还可给停靠窗体设置风格独特的标题栏和窗体控件(参见图

1.19)

有些应用程序(包括Qt Designer和Qt Linguist)经常使用停靠窗口。QMainWindow

为操作者提供保存并恢复停靠窗口和工具栏的位置的功能。这样,应用程序可以轻松恢复用

户首选工作环境。

1.7.6 对话框

对于特定操作,大多数 GUI 应用程序使用对话框来与用户交互。Qt 为大多数常见任

务提供了现成的对话框类和便利功能。我们稍后将提供一些 Qt 标准对话框的屏幕快照。

Qt 还为色彩选择和打印选项提供了标准对话框。

对话框提供以下三种操作方式:

1)模式对话框。此类对话框阻止向同一应用程序的其他可视窗口进行输入。用户必须

先关闭此对话框,然后才可访问该应用程序中的其他窗口。

2)非模式对话框。此类对话框的运行与其他窗口无关。

3)半模式对话框。此类对话框立即将控制权返回给调用程序。从用户角度来看,这些

对话框类似于模式对话框,但它们允许应用程序继续进行处理。这对进度对话框而言十分有

用。

通常,模式对话框按如下方式使用:

22

OptionsDialog dialog(&optionsData);

if (()) {

do_something(optionsData);

}

QFileDialog是一种高级文件选择对话框。它可以用来选择一个或多个本地文件或远程

文件(例如:使用FTP来选择),还包括诸如文件重命名和创建目录等功能。与大多数Qt

对话框类似,QFileDialog的大小可以重新调整,这样易于查看较长的文件名和目录。您可

以将应用程序设置成自动使用Windows和Max OS X系统中的本地文件对话框。

Qt还提供了其他常见的对话框:QMessageBox可以向用户提供信息,或者向用户显

示简单的选择选项(例如:“是”或“否”);QProgressDialog则可显示进度条和“取消”

按钮。

编程人员可以通过从QWidget派生子类或者从QDialog派生子类,或者使用Qt提

供的任一标准对话框创建自己的对话框。另外,Qt Designer还提供了对话框模板,帮助开

发人员从头开始进行设计。

图 1.20 Plastique样式显示的QFileDialog和QFontDialog对话框

图 1.21 Plastique样式显示的QMessageBox和QProgressDialog对话框

1.7.7 交互式帮助

现代应用程序经常使用不同形式的交互式帮助来阐明用户界面元素的目的。Qt提供了

两种机制来提供简单的帮助消息:工具提示和“这是什么?”帮助。

工具提示是黄色的小方框,如果鼠标指针停留在某一窗体的上方,则它会自动显示。由

于工具栏按钮几乎不与文本标签一起显示。因此,工具提示经常用来阐明工具栏按钮的目的。

23

下面,我们举例说明如何设置“保存”工具栏按钮的工具提示。

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

另外,在显示每个工具提示的同时,还可以在主窗口状态栏中显示更长的文本。

“这是什么?”帮助与工具提示类似,但它必须要用户请求(例如,按Shift+F1键,

然后单击某一窗体或菜单选项)才会显示。通常,“这是什么?”帮助比工具提示要更为详

细。下面,我们举例说明如何为“保存”工具栏按钮设置“这是什么?”文本。

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

QToolTip和 QWhatsThis类也可以用来实现更专业的操作,例如,提供动态工具提示,

根据鼠标所在窗体的位置显示不同的文本。

在线帮助浏览器可以提供某一应用程序的更多详细信息。QAssistantClient类则支持应

用程序使用Qt Assistant根据用户请求来显示用户指南的相关页面。

1.7.8 多文档界面

QMdiArea类支持多文档界面(MDI)功能。通常,该类可作为QMainWindow类的中

心窗体使用。

QMdiSubWindow类提供QMdiArea类的子窗体,该类可以包含任何类型的控件。

这些子窗体的边框与顶层窗体的边框的绘制方式类似,子MD 窗体的功能(例如:显示、

隐藏、最大化以及设置窗口标题)与普通顶层窗体相同。

QMdiArea提供了排列方式,例如,层叠和平铺。如果某一子窗体超出MDI区域,则

可将滚动条设置成自动显示。如果将子窗体最大化,则菜单栏中将显示边框按钮(例如,“最

小化”按钮)。

1.7.9 向导页

向导页用于指导用户执行常见的任务或过程,带领用户一步一步的浏览可选项并提供必

要的帮助。Qt提供了一组灵活直观的API,用于在每个支持的平台上建立专属的本地观感

的向导页。

一个典型的向导程序包含一个QWizard对象和一或多个赋予ID的QWizardPage对

象, 这样可以实现页面间的切换。QWizard类提供了超越基本的操作系统平台相关的观感

之外的外观定制功能。例如,该类还可控制每个页面呈现给用户的顺序。QWizardPage是

一个QWidget的子类,它提供了保存和验证用户输入的功能。

24

图 1.22 QWizard类创建本地观感的向导页面

1.7.10 设置

使用QSettings类,可以将用户设置以及其他应用程序设置轻松存储在磁盘中。在

Windows中,QSettings利用系统注册表来存储;在Mac OS中,它使用系统的

CFPreferences机制来存储;在其他平台中,设置则存储在文本文件中。

每个设定都用关键词存储。例如:关键词 /SoftwareInc/Zoomer/RecentFiles

可能包含最近使用过的文件列表。您也可存储布尔值、数字、Unicode 字符串以及

Unicode字符串列表。各种Qt数据类型均可与QSettings无缝使用,这些类型在存储时

将被序列化,稍后由应用程序读取。

1.7.11 多线程

GUI 应用程序经常使用多个线程:一个线程保持用户界面的响应,其他线程则执行耗

时冗长的活动,例如:读取大型文件并执行复杂的计算。您可以配置Qt来支持多线程,并

提供类来表示线程、互斥锁、信号灯、线程全局存储,另外还提供支持不同锁定机制的类。

许多Qt类都可重入,且Qt提供的许多功能是线程安全的。

Qt 4的元对象系统支持不同线程中的对象使用信号和槽进行通信,这样开发人员可以

创建单线程应用程序,这些应用程序稍后可以调整为多线程,而无需再重新设计。另外,组

件之间可以通过相互发送事件的方式实现跨线程的通信。也可以在线程之间传输特定类型的

对象。图

1.23

Qt 4 Mandelbrot 示例表明执行耗时冗长的任务时,如何使用线程保持用户界

面的响应。

图 1.23

使用线程保持用户界面的响应

25

1.7.12 桌面集成

使用Qt的桌面集成类,可以扩展应用程序,使其与用户桌面环境所提供的服务交互。

这些类包括QSystemTrayIcon(运行时间较长的应用程序经常使用此类,以便在系统托盘

中提供一致的指示器)和QDesktopServices(使用此类控制诸如mailto: 和 URLs

的资源由每个平台中最适合的应用程序来处理)。

QDialogButtonBox是Qt标准对话框中所使用的一个专业化的容器窗体,它可以根据

每个平台的风格准则来排列按钮。自定义对话框中也可以使用此部件。

1.8 Qt Designer(Qt设计师)

Qt Designer是Qt应用程序的一个图形用户界面设计工具。应用程序可以完全使用代

码编写,也可以使用Qt Designer加快开发过程。Qt Designer的架构以组件为基础,这

样开发人员便可以使用自定义的窗体和扩展程序来扩展Qt Designer,甚至还可将它集成至

各种开发环境中。

使用Qt Designer设计窗体十分简单。开发人员只需将控件从工具框拖到窗体,然后

使用标准编辑工具来选择、剪切、粘贴窗体并重新调整大小即可。然后,可以使用属性编辑

器来更改每个控件的属性。窗体的大小和精确位置无关紧要,开发人员只需选中窗体,并对

它们运用布局即可。例如,您可以选中一些按钮控件,并通过选择“横向排放”选项将它们

并列排放。采用这种方法,可以使设计更快速,设计完成后,控件会根据最终用户需要的窗

体大小正确缩放。

Qt Designer消除了用户界面设计中耗时冗长的“编译、链接和运行”周期。这样易于

更正或更改设计。使用Qt Designer的预览选项,开发人员可以查看设计的窗体在其他样

式下的显示效果;例如,Macintosh开发人员可以预览Windows样式的窗体。

Windows平台可以在Microsoft Visual Studio内充分享受到Qt Designer用户界面设

计所带来的便利。在Mac OS X中,开发人员则可在Apple's Xcode环境内使用Qt

Designer。另外,奇趣科技还为跨平台的EclipseTM集成环境开发了Qt的集成插件,以将

Qt Designer及其他Qt技术嵌入到集成环境框架中。

1.8.1 使用 Qt Designer

开发人员既可以创建“对话框”样式的应用程序、又可以创建带有菜单、工具栏、气球

帮助以及其他标准功能的“主窗口”样式的应用程序。Qt Designer提供了多种窗体模板,

开发人员可以创建自己的模板,确保某一应用程序或某一系列应用程序界面的一致性。编程

人员可以创建自己的自定义窗体,这些窗体可以轻松与Qt Designer集成。

Qt Designer支持采用基于窗体的方式来开发应用程序。窗体是由用户界面(.ui)文件

来表示的,这种文件既可以转换成C++并编译成一个应用程序,也可以在运行时加以处理,

从而生成动态用户界面。Qt 构建系统能将用户界面的编译构建过程自动化,使设计过程更

轻松。

26

图 1.24 停靠窗口模式中的 Qt Designer

1.8.2 Qt Assistant(Qt 助手)

Qt Designer的在线帮助是由Qt Assistant应用程序提供的。Qt Assistant可以显示整

个Qt的文档集,其运行方式类似于Web 浏览器。但与Web浏览器不同的是,Qt Assistant

采用了一种高级索引算法,可以全文本快速搜索所有相关文档。

27

图 1.25 Qt Assistant 所显示的某一页 Qt 4 文档

Qt的参考文档包括大约3,100页HTML文档,描述Qt的所有类和工具,并概述了Qt

编程的各个方面。

开发人员可以将Qt Assistant 部署为自有应用程序和文档集的帮助浏览器。使用

QAssistantClient 类,可以集成Qt Assistant。Qt Assistant使用QTextEdit来显示Qt的

HTML参考文档;如有必要,开发人员也可以使用此类来直接实现自己的帮助浏览器。

QTextEdit支持HTML 4.0的子集,它与Qt提供的富文本(RichText)类一起使用时,也

可以用来显示其他格式的文档。

1.8.3 GUI 应用程序示例

图 1.26“类层次结构”应用程序是一个典型的对话框式的应用程序,在此程序中,用户可

以选择一些选项(在此示例中是指选择路径),然后可以根据选项执行某些处理。

以下是该应用程序的完整代码。该窗体使用Qt Designer设计,并存储在.ui文件中。

uic将.ui文件转换成C++,这样使开发人员可专心于应用程序的功能。

尽管使用Qt Designer后,设计用户界面会变得更轻松,但通常还需要一些附加的应

用程序逻辑。通常,开发人员可以通过将uic生成的用户界面进行派生类并实现新功能的方

式来提供附加功能。

对话框的构造函数仅建立Qt Designer提供的用户界面,并为树状窗体创建两个标签。

28

图 1.26 简单类层次结构应用程序

ClassHierarchy::ClassHierarchy(QWidget *parent)

: QDialog(parent)

{

setupUi(this);

QStringList headings;

headings < < tr("Class") < < tr("Source file");

treeWidget->setHeaderLabels(headings);

}

on__clicked()函数是指调用setupUi()时,自动从对话框中的按钮连接至信

号的所有槽。以下槽仅更改列表控件中的项目:

void ClassHierarchy::on_addSearchPathButton_clicked()

{

QString path = QFileDialog::getExistingDirectory(

this, "Select a Directory", QDir::home().path());

if (!y() &&

searchPathBox->findItems(path, Qt::MatchExactly).count() == 0)

searchPathBox->addItem(path);

}

29

void ClassHierarchy::on_removeSearchPathButton_clicked()

{

delete searchPathBox->takeItem(searchPathBox->currentRow());

}

on_updateButton_clicked()槽使用在文件中找到的类(该类名与相关模式匹配)来

重新填充树状窗体:

void ClassHierarchy::on_updateButton_clicked()

{

QStringList fileNameFilter;

QRegExp classDef;

if (language->currentText() == "C++") {

fileNameFilter < < "*.h";

tern("bclasss+([A-Z_a-z0-9]+)s*"

"(?:{|:s*publics+([A-Z_a-z0-9]+))");

} else if (language->currentText() == "Java") {

fileNameFilter < < "*.java";

tern("bclasss+([A-Z_a-z0-9]+)s+extendss*"

"([A-Z_a-z0-9]+)");

}

();

treeWidget->clear();

for (int i = 0; i < searchPathBox->count(); i++) {

QDir dir = searchPathBox->item(i)->text();

QStringList names = ist(fileNameFilter);

for (int j = 0; j < (); j++) {

QFile file(th(names[j]));

if ((QIODevice::ReadOnly)) {

QString content = l();

int k = 0;

while ((k = n(content, k)) != -1) {

processClassDef((1), (2),

30

names[j]);

k++;

}

}

}

}

}

图 1.27使用Qt Designer编辑类层次结构窗口

在Qt Designer中,让“关闭”按钮与对话框的 accept() 槽相连。以下列出完整的

私有程序,这可以处理所有的类并将其插入至树状窗体中:

void ClassHierarchy::processClassDef(const QString &derived,

const QString &base, const QString &sourceFile )

{

QTreeWidgetItem *derivedItem = insertClass(derived, sourceFile);

if (!y()) {

QTreeWidgetItem *baseItem = insertClass(base, "");

if (derivedItem->parent() == 0) {

treeWidget->takeTopLevelItem(

treeWidget->indexOfTopLevelItem(derivedItem));

baseItem->addChild(derivedItem);

derivedItem->setText(1, sourceFile);

}

}

31

}

QTreeWidgetItem *ClassHierarchy::insertClass(const QString &name,

const QString &sourceFile)

{

if (classMap[name] == 0) {

QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);

item->setText(0, name);

item->setText(1, sourceFile);

treeWidget->setItemExpanded(item, true);

(name, item);

}

return classMap[name];

}

上述示例阐述了如何将用户界面“编译”进应用程序。也可以在运行时从.ui文件中动

态生成用户界面,这样开发人员可以创建可单一执行的应用程序,并针对不同用途对这些应

用程序定制化。

对于在使用Qt Designer时创建和编写应用程序而言,使用哪些工具来创建并编辑这

些应用程序的源代码则取决于每个开发人员的个人喜好;有的人喜欢利用Qt Designer提

供的集成功能在Microsoft Visual Studio或Apple's Xcode开发环境内来开发。

1.9 国际化

Qt完全支持Unicode这一国际化标准字符集。编程人员可以随意在应用程序中混合使

用阿拉伯语、英语、以色列语、日语、俄语以及其他Unicode所支持的语言。另外,Qt

还提供了其他工具来支持应用程序的翻译工作。

Qt提供了许多工具来简化翻译过程。使用从源代码中提取文本的工具,编程人员可以

轻松标记需要转换的用户可视文本。Qt Linguist是一个易于使用的GUI应用程序,它可以

读取代码中提取出的源文本,并向该文本提供要翻译的上下文信息。完成翻译后,Qt Linguist

将输出一个翻译文件,供应用程序使用。

32

图 1.28

使用不同语言显示的同一用户界面

Qt使用QString类来存储Unicode字符串,并在整个API和系统内部都使用此类。

QString 替换了const char *指针和std::string,而16位QChar则替换了char。Qt提

供了构造函数和运算符,自动在8 字符串之间进行转换。由于QString 对象可以隐式共享

(即“修改时复制”),因此编程人员可以使用值复制来创建对象,这样可以更快捷创建对象,

更好利用内存。

QString不仅仅只是16位字符串。它还提供了许多函数(例如:QChar::lower()和

QChar::isPunct())可以替换tolower()和ispunct(),可以处理所有Unicode。QRegExp

类负责提供Qt的正则表达式引擎,可以在正则表达式模式和目标字符串中使用Unicode

字符串。

Qt提供了区域支持,可以根据用户的地理位置和语言首选项对数字和字符串进行相应

转换。例如:如下代码显示了如何在两个不同的地域进行转换操作

QLocale iranian(QLocale::Persian, QLocale::Iran);

QString s1 = ng(195); // s1 == "

int n = (s1); // n == 195

QLocale norwegian(QLocale::Norwegian, QLocale::Norway);

QString s2 = ng(3.14); // s2 == "3,14" (comma)

double d = le(s2); // d == 3.14

QTextCodec子类负责在不同的编码以及字符集之间进行转换。Qt使用QTextCodec

来控制字体、输入/输出以及输入法;开发人员也可以根据自行需要来使用它。

QTextCodec支持各种不同的编码,包括汉语的Big5和GBK、日语的EUC-JP、JIS

33

"

和Shift-JIS、俄语的KOI8-R以及ISO-8859系列标准编码。通过提供字符映射表或者继承

QTextCodec 类的方式,开发人员可以添加自己的编码。

1.9.1 文本输入和显示

亚洲书写系统所需字符远远超过了键盘上所能提供的字符。在窗口系统级别中,一种名

叫输入法的软件负责将一系列按键转换成实际的字符。Qt自动支持已安装的输入方法。

Qt为屏幕中所显示的所有文本都提供了功能强大的文本显示引擎,包括最简单的标签

以及最复杂的富文本编辑器。该引擎支持各种高级功能,例如:特殊换行、双向编写以及变

音标记。它可以显示全球大部分书写系统,包括阿拉伯语、汉语、斯拉夫语、英语、希腊语、

以色列语、日语、韩语、拉丁语以及越南语。Qt会自动将系统安装的各种字体组合在一起,

显示多语言文本。

1.9.2 翻译程序

Qt提供了许多工具和函数,帮助开发人员开发出本地语言的应用程序。Qt本身大约包

含400个用户可视的字符串,对于这些字符串,奇趣科技公司提供了法语和德语翻译文件。

若要使一个ASCII字符串可以被翻译,则只需将它放在tr() 译函数中即可;例如:

saveButton->setText(tr("Save"));

如果有翻译字符,则tr()将尝试使用翻译字符来替换字符串文字(例如,“Save”);否

则它将使用原文本。例如,将英语视为源语言,汉语视为目标语言。tr()参数将从应用程序

的默认编码转换成Unicode。作为备选方法,可以使用trUtf8()函数向翻译系统提供编码为

UTF-8的文本。tr()的常规语法为:

Context::tr("source text", "comment")

其中“context”是指QObject子类的名称。它通常可以省略,在省略的情况下,包

含tr()调用的类将视为上下文。“source text”是指要翻译的文本。“comment”是可选的;

它与上下文一起,向各翻译人员提供附加信息。另外,您还可以使用一个可选参数来指定整

数值,帮助翻译复数格式:

Context::tr("%n message(s) saved", "number of saved messages",

())

其中“(s)”这一特殊符号表示将使用复数格式,这样确保系统针对用户语言使用指定

整数的适当文本。翻译内容存储在QTranslator 对象中,该对象使用磁盘系统上的.qm文

件(Qt翻译文件)。每个.qm文件都包含特定语言的翻译内容。可以根据实际情况或用户

喜好在运行时选择特定语言。

Qt 提供了三种工具来准备.qm 文件:lupdate、Qt Linguist和 lrelease。

1)lupdate从源代码(包括Qt Designer的.ui文件)中提取一系列项目,每个项目

均包含一个上下文、多个源文本以及一条注释,提取后生成一个.ts文件(即:“Translation

Source”文件)。这些文件均采用可直接阅读的XML 格式。

34

2)翻译人员使用Qt Linguist来翻译.ts文件中的源文本。

3).qm文件是经过高压缩的文件,在.ts文件上运行lrelease,即可生成此文件。

在应用程序的生命周期中,经常有必要需要重复上述步骤。如果经常运行lupdate,

也会十分安全,其原因是:lupdate 将重新使用现有翻译内容,并标记、而不是删掉那些

过时不再用的源文本的翻译内容。lupdate 还会检测到源文本中出现的任何细微变化,并

自动向相应的翻译内容发出建议。系统会将这些翻译内容标记为“未完成”,这样,翻译人

员可以轻松对这些内容进行检查。

1.9.3 Qt Linguist

Qt Linguist应用程序是一种帮助翻译人员来翻译Qt应用程序的工具。Qt应用程序的

翻译文件通常储存在.ts格式的文件中,此外,Qt Linguist还支持XML格式的本地化交互文

件格式(XLIFF),从而支持其他第三方的应用和服务的拓展。

使用Qt Linguist,翻译人员可以方便快捷地编辑.ts文件。在Qt Linguist应用程序窗口

的左侧,已列出.ts文件的上下文。在窗口右上角,则显示了当前上下文的源文本列表以及

翻译内容。通过选中某一源文本,翻译人员可以开始翻译,并将此任务标记为“已完成”或

“未完成”,然后继续执行下一未完成的翻译。Qt为所有常见导航选项(例如“完成并转到

下一个”和“下一个未完成”)都提供了键盘快捷键。翻译人员可依据其个人喜好随意调整

用户界面的固定窗口位置。

应用程序经常在不同的源文本中多次使用同一段落。Qt Linguist可以根据窗口底部显

示的以前翻译过的字符串和预先定义的翻译内容自动显示合理猜测内容。猜测内容往往是一

个良好的起点,有助于翻译人员始终一致地翻译类似文本。常见的翻译内容也可以存储在词

汇表中,有助于更高效快速地翻译未来的应用程序。另外,Qt Linguist可以有选择性地验

证翻译内容,确保快捷键和句末标点翻译正确。

35

图 1.29使用Qt Linguist 翻译成中文

1.10 布局

相比于使用固定尺寸和位置,布局提供了功能强大且极具灵活性的另一种方案。使用布

局后,编程人员无需计算尺寸和位置,布局可以自动进行调整,符合用户屏幕、语言以及字

体的要求。

Qt的布局管理器负责在父控件区域内构建子控件。这些管理器可以使顶层控件自动定

位并重新调整子控件、保持顶层控件敏感度最小化的变化和默认尺寸,并可在内容或文本字

体更改时自动重新定位。在Qt Designer中,完全可以使用布局管理器来定位控件。

图 1.30以不同尺寸显示的同一对话框

布局对于国际化也非常有用。系统使用固定的尺寸和位置的情况下,经常发生文本翻译

36

后变长而截断文本的现象(请参见图 1.28);使用布局,子控件可以自动重新调整大小。另

外,为了向采用从右至左书写系统的用户提供更为自然的显示效果,可以将控件的位置反转

过来。

1.10.1 内建布局管理器

Qt的布局管理器可以将控件以及其他布局排列为横向,纵向或网格中。

¾ QHBoxLayout按从左至右的顺序将管理的控件横放在一行中。

¾ QVBoxLayout按从上至下的顺序将管理的控件竖放在一列中。

¾ QGridLayout将管理的控件放在可扩展的单元格中,这样一来,如有必要,控件

可以跨越多个单元。

每个内建布局管理器均支持控件在分配的范围内横向、纵向对齐,这样只需使用简单的

布局和对齐属性,即可自定义用户界面的外观。

图 1.31使用QHBoxLayout、QVBoxLayout和 QGridLayout布局管理器排列的控件

在大多数情况下,Qt的布局管理器将为管理的控件选择最优尺寸,以便窗口可以顺利

重新调整大小。如果默认值不合理,那么开发人员可以使用以下机制优化布局:

1)为某些子控件设置最小尺寸、最大尺寸或固定尺寸。

2)添加拉伸项目或间距项目。这些项目将填补布局中的空白区域。

3)更改子控件的尺寸规则。通过调用QWidget::setSizePolicy(),编程人员可以采用

最优方式重新设置子控件的尺寸变化行为。可以根据布局中其他控件来扩大、缩小子控件,

或者使其尺寸不变。

4)更改子控件的尺寸提示。QWidget::sizeHint()和QWidget::minimum- SizeHint()

可以根据控件的内容返回其首选尺寸和首选最小尺寸。Qt内建的控件已经相应的提供了合

适实现。

5)设置拉伸因子。拉伸因子支持子控件的相对增长;例如,将2/3的任何多余的可用

空间分配给A控件,将1/3的空间分配给B控件。

另外,编程人员也可以设置被布局管理的控件之间的“间距”和整个布局周围的“空白”。

默认情况下,Qt Designer使用与上下文相关的行业标准值。

此外,布局还可以以从右至左或从下至上的方式运行。对于支持从右至左书写系统(例

如,阿拉伯语和以色列语)的国际化应用程序而言,从右至左布局十分便利。内建布局管理

37

器与Qt的样式系统完全集成,可在反转显示中提供一致的观感。

1.10.2 嵌套式布局

布局可以嵌套至任意级别中。图 1.30举例以两种不同尺寸显示了一个对话框。该对话

框使用了三种布局:QVBoxLayout,负责将按钮集中在一起、QHBoxLayout,负责将国

家/地区列表视图与按钮集中在一起,和QVBoxLayout,负责将“选择国家地区”标签与其

余控件集中在一起。拉伸项目则负责维护“取消”和“帮助”按钮之间的间距。

图 1.32

使用布局之后的效果图。在前两个图片中,显示了同一个未使用布局的原英语文本对话

框和法语文本对话框;法语文本被截断了。在右边的图片中,布局中含有标签,法语文本显示完

整正确。

图 1.32 嵌套式布局示例

上述对话框的控件和布局是使用以下代码创建的:

QVBoxLayout *buttonBox = new QVBoxLayout;

buttonBox->setSpacing(6);

buttonBox->addWidget(new QPushButton(tr("&OK")));

buttonBox->addWidget(new QPushButton(tr("&Cancel")));

buttonBox->addStretch(1);

buttonBox->addWidget(new QPushButton(tr("Help")));

QListWidget *countryList = new QListWidget(this);

countryList->addItem(tr("Canada"));

/* ... */

countryList->addItem(tr("United States of America"));

QHBoxLayout *middleBox = new QHBoxLayout;

middleBox->setSpacing(11);

middleBox->addWidget(countryList);

middleBox->addLayout(buttonBox);

QVBoxLayout *topLevelBox = new QVBoxLayout;

topLevelBox->setSpacing(11);

topLevelBox->setMargin(6);

38

topLevelBox->addWidget(new QLabel(tr("Select a country")));

topLevelBox->addLayout(middleBox);

setLayout(topLevelBox);

使用Qt后,布置控件变得十分容易。因此,编程人员几乎无需使用固定定位。开发人

员通过继承QLayout类,可以编写自定义的布局管理器。Qt的布局示例显示了两个自定

义布局管理器:一个是边框布局,它将子控件放置在罗盘的点中;另一个是顺序布局,它象

放置文字一样将控件放在页面中。编程人员可以使用并修改这些布局,为窗体创建新的布局

策略。

Qt还提供了QSplitter拆分条,最终用户可以对其进行细致操作。在某些设计情况下,

QSplitter比布局管理器更具优越性。

若要进行完整全面的控制,也可以重新实现 QWidget::resizeEvent()并调用每个子控

件中的QWidget::setGeometry(),手动设置布局。

1.11 样式和主题

Qt针对应用程序的外观自动使用本地桌面样式。Qt应用程序尊重用户对色彩、字体、

声音以及其他桌面设置的首选项。Qt编程人员可以自由使用提供的任一样式,并且可以覆

盖任何首选项。使用Qt功能强大的样式引擎,编程人员可以修改现有样式或实施自己的样

式。

样式负责实施用户界面在特定平台中的外观。样式是QStyle子类,负责实施基本的绘

图功能(例如,绘制边框、按钮和图像等)。Qt支持所有窗体以最快的速度灵活地绘制本身。

1.11.1 内建样式

Qt提供了以下内建样式:CDE、Cleanlooks、Motif、Mac OS X、Plastique、Windows

和Windows XP,Windows Vista。默认情况下,Qt针对用户的平台和桌面环境使用适当

的样式。另外,应用程序开发人员也可以通过编程方式来选择样式,或者由用户通过使用

“–style”命令行选项来选择。

图 1.33采用不同本地样式显示的 Comboboxes

样式与用户桌面设置保持一致,包括:用户对色彩、字体以及声音等的首选项。Qt自

动调整至计算机的活动主题。例如,对于菜单和工具提示,Qt支持滚动操作和淡化过渡效

果。Windows XP和 Mac OS样式以本地样式管理器为基础建立,仅在相关平台中可用。

其他样式是由Qt仿真的,可随处使用。

在大多数现代化的X11平台中,其默认样式为Plastique,该样式由KDE的Plastik窗

体样式生成,专门为大多数Linux和Unix桌面而设计。在GNOME桌面环境中,Qt应用

程序的默认样式为Cleanlooks,这种样式旨在类似于GNOME的Clearlooks主题。

39

Qt的内建窗体可识别样式。自定义窗体和对话框几乎总是既包括内建窗体,又包括布

局,而且它们可以自动调整以适应所使用的样式。开发人员几乎无需从头开始编写自定义窗

体,相反,他们可以使用QStyle来绘制基本的用户界面元素,而无需直接绘制原始图形基

原。

QStyle支持从右至左的语言。Qt根据加载的转换文件,自动使用从右至左的窗体,而

不是使用通常使用的默认从左至右的方案。在此模式中,用户可以指定“-reverse”命令行

选项来运行各个应用程序。另外,使用反转模式时,性能良好的样式会向窗体提交适合于用

户桌面环境的光亮区域和阴影区域。

图 1.34 样式表更改

1.11.2 窗体的样式表

Qt 4.3开始支持在大多数标准窗体中使用样式表。样式表是使用与级联样式表(CSS)类

似的语言编写的文本描述,它可以用来自定义窗体的外观,其方式大致类似于使用CSS描

述来自定义HTML(使用WWW浏览器来提交)的方式。通过styleSheet属性(可从QWidget

及其子类中获得)可以访问每个窗体的样式表,使用这一方式,可以在运行应用程序时,轻

松地将自定义功能运用到可识别样式的窗体中。由于此属性在Qt Designer中还可用于编

辑。因此,图形设计人员可以直接控制应用程序的外观。在许多常见情况中,如果需要自定

义标准窗体,则只需使用样式表,便无需编写自定义样式。

1.11.3 自定义样式

使用自定义样式,可以为某一应用程序或某一系列应用程序提供独特的外观。通过将

QStyle、QCommonStyle或其任何一个子类进行细分类,可以自定义样式。如果从适当的

基础类中重新实施一或两种虚拟功能,则可对现有样式进行轻松的细微修改。

QStyle为每个用来绘制窗体的成员组件提供信息,这样,可以创建并调整高度自定义

的样式。

Qt的本地平台样式适合于大多数应用程序。但在某些情况下,为了达到特殊的外观,

有必要覆盖默认样式。设置应用程序的样式十分简单,例如:

QApplication::setStyle(new MyCustomStyle);

40

样式也可以编译为插件。使用Qt Designer中的自定义样式,插件即可预览窗体,而

无需重新编译Qt或Qt Designer本身。使用样式插件,即可更改现有Qt应用程序的样式,

而无需重新编译该应用程序。使用这一方法,应用程序(例如,“Qt 4 样式”示例和qtconfig

工具)可以动态启动样式,为每个可用样式提供预览图形。

图 1.35 Qt内建样式和自定义样式比较

41


本文标签: 使用 窗体 应用程序