The Book of QT4 翻译

25 篇文章 0 订阅

The Book of QT4 翻译:1.1 我们的第一个QT程序

The Book of QT4 翻译

QT程序设计艺术

 

---------------------------------------------------------------------------------

原名:The Book of QT 4:The Art of Building Qt Applications

译名:The Book of QT 4中文版:QT程序设计艺术

---------------------------------------------------------------------------------

 

第一章基础,工具和第一行代码

 

**********************************************************************
******************* 1.1
我们的第一个QT程序
********************************
**********************************************************************

遵照传统的编程书籍和教程的做法,本书也必须以一个“Hello World程序开始。这个最小的QT程序,我们保存在一个名为main.cpp的文件中,只是简单的打开一个窗口。显示文本HelloWorld!代码如下:

 

 1// helloWorld/main.cpp
 2 #include <QApplication>
 3#include <QLabel>
 4 int main(int argc, char *argv[])
 5{
 6QApplication a(argc, argv);
 7QLabel label("Hello World");
 8label.show();
 9 return a.exec();
10}

 

为达到这个目的,开头两行代码包含了我们将要在下面的代码中使用的QT类的头文件。在这个程序中,头文件包含了QApplicationQLabel类的接口描述。

QT4中,每个QT类都有一个对应的头文件,以标准的.h扩展名结尾,文件名和类文件名完全一致。当你使用#include指令时,确保头文件的大小写是正确的。

第四行的前面是一个典型的QT程序的main()函数。首先你创建了一个QApplication对象并且将用户执行程序的命令行参数传递给它的构造函数。所有的GUI程序都必须依赖一个QApplication对象,因为,不像其它的东西,QApplication使得事件循环可用。这个循环使得程序在窗口被关闭前一直可以持续运行。

下一行我们创建了一个用于显示“HelloWorld!”文本的QLabel对象。开始时,这个对象是不可见的。我们必须调用show()函数使它在窗口中可见,正如下图所显示的:

最后我们调用exec()开始事件循环,事件循环负责转发应用程序的事件到合适的对象。这些事件由用户行为触发,例如点击一个按钮。在我们的第一个程序中,事件处理完全留给了QT系统。1.3节将向你展示如何实现用户交互。

QApplication对象的quit()方法被调用时,事件循环就结束了。在这个例子中,事件循环结束于应用程序的主窗口(在本例中就是显示文本的标签)关闭和从内存中清除时。

 

1.1.1 编译一个QT程序

 

当编译这个程序时,你面临一个问题:QT支持许多不同的平台,编译的过程对每个系统来说都有点不同。QT的提供商奇趣怪哦纳斯通过一个简单的程序解决了这个问题:使用一个跨平台的基础工具:qmake来创建工程。

qmake从工程文件生成的Makefile文件完全独立于程序实际的编译平台,是与操作系统无关的。生成的Makefile文件包括了在特定平台上编译C++程序代码所需要的全部信息。(在Windows系统上,qmake也可以生成Visual Studio的工程文件。)

使用qmake生成工程文件和Makefile文件

要为“HelloWorld程序生成工程文件,使用qmake-project选项就足够了。请打开命令行切换到包含源文件的当前目录。然后输入如下命令(假设源文件在D盘的Documents\helloWorld目录):

 

D:\Documents\helloWorld>qmake -project

 

这个命令将生成一个名为helloWorld.pro的文件(默认与源文件所在目录同名),该文件内容如下:

 

#helloWorld/helloWorld.pro
#####################################
# Automatically generated by qmake
#####################################
TEMPLATE = app
CONFIG -= moc
DEPENDPATH += .
INCLUDEPATH += .
# Input
SOURCES += main.cpp

 

有趣的条目是TEMPLATESOURCESTEMPLATE的值决定了我们想要创建应用程序还是库文件,SOURCES的值决定了工程包含的源文件。

简单的运行qmake就可以从工程文件产生Makefile文件,如下:


D:\Documents\helloWorld>qmake

 

Windows系统下,这个命令将产生三个文件:MakefileMakefile.DebugMakefile.Release。这里的Makefile文件是一个指向其它两个文件元文件(metafile)。Makefile.DebugMakefile.Release描述了如何从工程文件构建程序。

Unix平台上(包括LinuxMac OS),qmake只产生Makefile文件,该文件创建包含调试信息的可执行文件,除非程序使用的QT库文件的调试版本丢失。要确认是否安装了调试版本,在Unix系统上你可以搜索QT库文件以_debug.so结尾的调试版本,例如libQtCore_debug.soQtCore库文件的调试版。在Windows系统上,你可以查看以d结尾的DLL文件,例如,qtcored4.dllQtCore的调试版本。点击开始菜单的QT目录的构建调试版库文件确保QT构建了调试版本的库文件。

此外,为了在UnixWindows平台达到同样的效果,不仅要确保调试版本的库文件可用,还要在工程文件中加入下面一行:


CONFIG += debug_and_release

 

+=操作符此处的含义与在C++中相同,它在没有覆盖已有值的情况下给CONFIG变量添加了一个额外的项。类似的,-=操作符用于一处一个独立的项。

一个可选的方案是,在运行qmake前,设置一个值为'CONFIG += debug_and_release'的环境变量QMAKEFLAGS(不要忘了撇号)。但是将该项放在工程文件中可以简化使用版本控制(如CVS,SubversionVisual Source Safe)系统进行多人协作开发的情况。

如果你仅仅想要可执行文件的调试版本,CONFIG变量可以包含值debug。同样地,你也可以仅仅产生没有调试信息的更适合于最终用户的发行版。

编译工程

make命令默认产生调试版本,当跟着release目标是产生release版本,如下:

D:\Documents\helloWorld>make(相当于make debug
D:\Documents\helloWorld>make release

 

如果你使用Microsoft Visual Studio,也可以把make换成nmake。在任何一种情况下,可执行文件都储存在release或者debug子目录。

一旦编译完成,在Unix系统下可以用./release/helloWorld或者./debug/helloWorld执行文件,打开的窗口如1.1节(P26)的图所示。

 

The Book of QT4 翻译:1.2 布局,对象层级和内存管理

The Book of QT4 翻译

QT程序设计艺术

---------------------------------------------------------------------------------

原名:The Book of QT 4:The Art of Building Qt Applications

译名:The Book of QT 4中文版:QT程序设计艺术

---------------------------------------------------------------------------------

第一章基础,工具和第一行代码


*******************************************************************
******************* 1.2
布局,对象层级和内存管理 *************************
*******************************************************************

 

1.2.1 如何自动布置窗口部件(也可以叫控件)


为了扩展我们第一节的HelloWorld程序使它不仅仅是显示一个文本标签,而是像图1.2那样按顺序显示两个QLabel,我们使用QT的布局系统。这个系统自动安排GUI元素:包括窗口小部件和控件。类似于在印刷领域中的术语,我们称之为布局。


1.2显示的界面的源代码如下:

 

代码

 1// layout/main.cpp
 2 #include <QApplication>
 3#include <QVBoxLayout>
 4#include <QLabel>
 5 int main(int argc, char *argv[])
 6{
 7QApplication a(argc, argv);
 8QWidget window;
 9QVBoxLayout* mainLayout = new QVBoxLayout(&window);
10QLabel* label1 = new QLabel("One");
11QLabel* label2 = new QLabel("Two");
12mainLayout->addWidget(label1);
13mainLayout->addWidget(label2);
14window.show();
15 return a.exec();
16}

 

 

除了1.1节中我们已经使用过的QApplicationQLabel,我们现在还要包含另外一个用来垂直排列小部件的类:QVBoxLayout,名字中的V代表垂直(vertical)。这一次我们使用QWidget对象作为应用程序的主窗口,而不是上一节的QLabel对象。使用这个名字仅仅是出于习惯。只需要两步,QWidget对象就可以成为一个独立的窗口。第一步,调用QWidget对象的构造器,如果像在本例中一样没有提供参数,新对象就没有父窗口,因此,处于对象继承层次的最顶层。第二步,小部件只有调用show()方法显示出来时才能成为一个窗口。

创建完QWidget后,我们创建了一个QVBoxLayout对象。我们在这里使用new操作符代替:
QVBoxLayout mainLayout(&window);

具体将在下面的1.2.2节中解释。因此,新创建的QVBoxLayout知道这表示window窗口的布局,QWidget对象的指针作为一个参数传给了它的构造器。

类似地,我们还创建了OneTwo两个文本标签对象。为了使他们接受窗口布局对象的管理,我们通过QVBoxLayout对象的addWidget()方法将它们添加到布局中。


这个程序除此之外的部分与我们的第一个例子几乎没有区别。注意到我们仅仅调用了show()方法使得QWidget对象可见,这将使得QWidget包含的所有窗口部件都显示在屏幕上,在本例中就是那两个标签。

最后,我们像以前一样开始了事件循环,而且通过事件循环传回来一个返回值作为应用程序的返回值。简单的返回0将立即结束程序并且不再显示窗口。

这个程序显示了使用布局管理的主要优点:你不必关注窗口部件的确切位置。另外,用户可以缩放布局窗口,布局管理器将自动的调整窗口组件,确保他们合理的填充可用空间,而不需要开发者写详细的代码来实现。

布局管理也允许开发者自定义单个部件的行为:例如,当一个控件应该占满尽可能多的空间,或者需要限制大小时,又或者处理不需要太多垂直空间的部件,如CheckBox时。第五章详细介绍了如何实现这样的布局。

 

1.2.2 对象层次的内存管理

 

1.2展示的应用程不仅在自动布局方面异于第一节的HelloWorld程序,在其它方面也有显著的不同。变量声明QWidget window用于分配内存给QWidget对象,但给QVBoxLayoutQLabel对象时,我们使用了new操作符,使用:
QVBoxLayout* mainLayout = new QVBoxLayout(&window);
而不是:
QVBoxLayout mainLayout(&window);
创建布局对象。

我们详述这个是因为C++不提供自动内存管理。一般来说,程序员必须自己小心处理。然而,正如下面提到的,QT接管了部分的内存管理工作。所有的类对象都继承自QObject形成了一个树形结构:对象可以拥有子对象。如果一个对象删除了,QT自动删除它所有的子对象,以及子对象的后代。

                    QWidget
|                          |                 |
QVBoxLayout    QLabel      QLabel

 

从另一方面说,如果对象树的根节点消失了,QT会自动删除整个树。这缓解了程序员跟踪对象后代和释放它们占用的内存的负担。然而,为了使自动内存管理生效,所有的后代(以及后代的后代)都必须分配在堆(Heap)上,即必须使用new操作符创建它们。使用new操作符创建的对象都引用了一个指向堆的指针。这就是为什么mainLayout被声明为一个指向QVBoxLayout的指针,而不是一个QVBoxLayout对象。

不在堆上创建对象(即不使用new分配内存)是一个初学者的常见误区:窗口部件只被创建在栈(Stack)上,(例如,在一个类的构造器中),当进程结束时他们被编译器删除。虽然应用程序并不仅是简单的产生部件,但它们对于人来说,永远是不可见的。

而且,这个声明不仅仅创建了一个QVBoxLayout对象,也使它成为Qwidget对象窗口的子对象,通过QVBoxLayout类的构造器实现。与此相反,两个QLabel对象初始化的时候没有父对象,QLabel构造器仅仅初始化了标签的文本:
QLabel* label1 = new QLabel("One");

我们随后使用QVBoxLayout::addWidget()方法确保QWidget对象承担作为每个新标签父对象的责任。(事实上,一个窗口部件包含的GUI元素必须成为该对象的子对象。由此,QWidget对象成为QLabel对象的父对象,而不是我们可能以为的QVBoxLayout对象的子对象。)图1.3展示的树结构的创建过程就是这样的。

窗口对象的子对象,布局对象和两个标签都必须使用new操作符在堆上创建从另一方面说,我们使用QWidget window;在栈上创建了窗口.因此当应用程序关闭时我们不必手动删除它。(只有当对象没有父对象是你才可以这样做。)因而,在多数情况下,你应该使用new操作符创建继承自QObject的类对象。

 

1.2.3 其它布局类型

 

QHBoxLayout类用来水平布局元素,和用来垂直布局元素的QVBoxLayout类一样,它的界面也类似于QVBoxLayout。如果你用QHBoxLayout替换掉例子中的QVBoxLayout,图1.2将会显示成如下图所示:


这里还有一个使用QGridLayout网格布局的例子:

 

  代码

 1// gridLayout/main.cpp
 2 #include <QApplication>
 3#include <QGridLayout>
 4#include <QLabel>
 5 int main(int argc, char *argv[])
 6{
 7QApplication a(argc, argv);
 8QWidget window;
 9QGridLayout* mainLayout = new QGridLayout(&window);
10QLabel* label1 = new QLabel("One");
11QLabel* label2 = new QLabel("Two");
12QLabel* label3 = new QLabel("Three");
13QLabel* label4 = new QLabel("Four");
14QLabel* label5 = new QLabel("Five");
15QLabel* label6 = new QLabel("Six");
16mainLayout->addWidget(label1, 0, 0);
17mainLayout->addWidget(label2, 0, 1);
18mainLayout->addWidget(label3, 1, 0);
19mainLayout->addWidget(label4, 1, 1);
20mainLayout->addWidget(label5, 2, 0);
21mainLayout->addWidget(label6, 2, 1);
22window.show();
23 return a.exec();
24}

 1// gridLayout/main.cpp
 2 #include <QApplication>
 3#include <QGridLayout>
 4#include <QLabel>
 5 int main(int argc, char *argv[])
 6{
 7QApplication a(argc, argv);
 8QWidget window;
 9QGridLayout* mainLayout = new QGridLayout(&window);
10QLabel* label1 = new QLabel("One");
11QLabel* label2 = new QLabel("Two");
12QLabel* label3 = new QLabel("Three");
13QLabel* label4 = new QLabel("Four");
14QLabel* label5 = new QLabel("Five");
15QLabel* label6 = new QLabel("Six");
16mainLayout->addWidget(label1, 0, 0);
17mainLayout->addWidget(label2, 0, 1);
18mainLayout->addWidget(label3, 1, 0);
19mainLayout->addWidget(label4, 1, 1);
20mainLayout->addWidget(label5, 2, 0);
21mainLayout->addWidget(label6, 2, 1);
22window.show();
23 return a.exec();
24}

 

这个程序和前一个例子差不多,只不过用QGridLayout取代了QVBoxLayout作为容器,这次包含了六个QLabel对象。与水平或垂直布局类的addWidget()方法不同的是,QGridLayout::addWidget()方法需要三个参数:要被指派的部件,以及该部件放置在在网格中的行和列的位置。网格的第一个格子的坐标是(0,0),位于左上角。结果如图1.5所示:

如果文本Five无法正确显示,可能的原因是源文件是以UTF-8编码格式保存的。你需要转换为ISO-8859-1或者 ISO-8859-15格式。在KDE的编辑器Kate中,这个选项可以在另存为对话框中看到。(Windows系统中也是类似的。)

你将在第五章中了解到关于布局管理的更多细节。我将介绍如何设计复杂的布局,例如通过嵌套布局。还将介绍手动布局,分裂器(Splitters)和QStackedLayout类。

分裂器的行为类似于水平布局和垂直布局,但是在额外的空白空间里显示被称之为手柄(handle)的东西。用户可以直接拖动手柄使对面的部件获得根多的空间。当拖动一个手柄时,窗口部件朝手柄拖动的方向收缩。

另一方面,QStackedLayout类管理一些面板,这些面板每个都可以包含多组部件,但只有一个可以显示。设置对话框可以使用这个类,例如,当用户选择这样一个设置对话框左边面板的一个目录时,右边的面板显示用来更改所选目录选项的窗口部件。当用户更改左边的目录时,QStackedLayout对象知道应该改在右边显示一个不同的页面。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值