QT一个月自学教程

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

百度文库- 让每个人平等地提升自我
1
目录
第一章Qt简介 (3)
选择Qt库 (3)
安装Qt库 (4)
带你进入Qt的世界 (5)
第二章创建对话框 (11)
对话框 (11)
深入信号和槽 (16)
快速设计对话框 (18)
可变形状的对话框 (23)
动态对话框设计(下列方法基本不用) (30)
内置控件和对话框类 (31)
第三章创建主窗口 (37)
子类化QMainWindow (38)
创建菜单和工具条 (41)
使用对话框 (49)
保存设置 (54)
多文档 (56)
启动画面 (59)
实现Edit菜单 (62)
其它菜单项 (66)
第五章创建自定义部件 (75)
自定义部件 (75)
从QWidget类继承 (77)
将自定义部件集成到Qt Designer中 (85)
分割控件 (94)
滚动区域 (97)
可停靠控件和工具栏 (98)
多文档界面 (100)
第七章事件处理 (109)
重写事件处理函数 (109)
事件过滤器 (113)
忙时响应 (115)
第八章2D图形 (119)
绘图类QPainter (119)
百度文库- 让每个人平等地提升自我
2
坐标变换 (122)
第九章拖拽功能 (131)
支持多拽 (131)
剪切板 (138)
第十章数据视图类 (141)
使用数据视图类 (142)
预定义模型类 (148)
第十一章容器类 (155)
顺序容器 (155)
关联容器 (162)
通用算法 (165)
字符串, 字符数组, 变量 (167)
第十二章输入/输出 (173)
读写二进制数据 (174)
遍历目录 (178)
第十三章进程与进程间通信 (181)
使用QProcess (181)
同步线程 (186)
在次线程中使用Qt的类 (191)
写HTTP客户端 (200)
写TCP客户/服务器应用程序 (203)
发送和接收UDP数据报 (212)
第十六章提供在线帮助 (217)
工具提示、状态提示和“What’ This?”帮助 (217)
利用Web浏览器提供在线帮助 (219)
将QTextBrowser作为简单的帮助引擎 (221)
使用Qt Assistant提供强大的在线帮助 (223)
百度文库- 让每个人平等地提升自我
3 第一章Qt简介
●选择Qt库
●可移植性
●带你进入Qt的世界
选择Qt库
GUI工具包(或GUI库)是构造图形用户界面(程序)所使用的一套按钮、滚动条、菜单和其它对象的集合。

在UNIX系统里,有很多可供使用的GUI库,其中之一就是Qt库——一个基于C++编程语言的工具包。

由于Qt是基于C++,因此它具有速度快,易于使用,可移植性好的特性。

所以,当需要开发UNIX或MS Windows环境下的GUI程序时,Qt是最佳选择。

1.1.1可移植性
Qt不只是适用于UNIX,它同样适用于MS WINDOWS。

如果你是一个以编程为生的程序员,那么你的目标一定是吸引尽可能多的用户,以使他们有机会购买你的产品。

如果你的主要平台是MS WINDOWS,你很可能使用标准库——MFC,但是你这样做,可能使你失去世界上几百万的UNIX用户。

相反,如果你的主要平台是UNIX,你可以使用其它工具包,如Gtk+或Xforms,但这样会使你失去更多的WINDOWS 用户。

那么,最好的方法就是选择一个既适用于WINDOWS又适用于UNIX的GUI工具包,Qt就是一个最好的选择。

1.1.2 易用性
如前所述,Qt是一个C++工具包,它由几百个C++类构成,你在程序中可以使用这些类,因为C++是面向对象的编程的语言,而Qt是基于C++构造。

所以,Qt也具有OOP的所有优点。

(OOP - Object Oriented Programming 面向对象编程)
1.1.3 运行速度
Qt非常容易使用,且也具有很快的速度。

这两方面通常不能同时达到。

当我们谈论其他GUI开发包时,易用常意味着低速,而难用则常意味着快速(或者从另一个方面讲,低速意味着易用,而快速则意味着难以使用),但当谈论Qt时,其易用性和快速是密不可分的,这一优点要归功于Qt开发者的辛苦工作,他们花费了大量时间来优化他们的产品。

Qt比其他许多GUI工具包运行速度快的另一原因是它的实现方式,Qt是一个GUI仿真工具包,这意味着它不使用任何本地工具包作调用。

Qt使用各自平台上的低级绘图函数仿真MS Windows和Motif(商用UNIX的标准GUI库),当然,这能够提高程序速度。

其他适用于多种平台上的工具包,如wxWindows,
百度文库- 让每个人平等地提升自我
则是适用API层或API仿真,这些方法均以不同的方式使用本地工具包,从而降低程序的运行速度。

安装Qt库
Qt安装过程非常简单。

本节介绍怎样在UNIX/Linux系统上安装Qt。

1.2.1 编译和安装
从的开发包,然后自己编译它。

这样能够确保Qt库被正确安装,并且保证所安装的软件版本包含来自Troll Tech公司的最新功能和改进。

现在可以开始下载。

当下载窗口从屏幕消失后,下载完成,便可以开始安转了。

将最新下载的文件复制到/usr/local目录中,当然你也可以自己新建一个目录,我就把4.4.3复制到/QT目录下面。

那下面进到QT目录下,并执行下面的命令。

#tar –zxvf 4.4.3该命令将文件解压到一个子目录中,然后将目录名字更改为qt-x11-4.4.3
#mv 4.4.3 qt然后进入qt-x11-4.4.3目录中
#cd qt-x11-4.4.3
#./configure
如果你想查看./configure的相关配置命令,可以输入
#./configure –help (查看配置)
接下来就可以通过makefile来编译Qt库了
当你看到
Qt is now configured for building. Just run 'gmake'.
Once everything is built, you must run 'gmake install'.
Qt will be installed into /usr/local/Trolltech/Qt-4.4.3
To reconfigure, run 'gmake confclean' and 'configure'
你的confiure也就完成了,在执行configure的过程中,可能会出现错误,导致错误的原因或许是g++编译版本的问题,我使用的g++编译器版本是Linux自带的4.1.1版本的g++,可以顺利通过。

下一步就是执行#make了(这是一个很漫长的过程)。

经过漫长的等待,终于编译完了,紧接着执行
#make install
然后设置环境变量
打开/etc/profile或者.bashrc文件,在文件末尾加上:
export QTDIR=/usr/local/Trolltech/Qt-4.4.3
export PATH=$QTDIR/bin:$PATH
export LD_LIBRARY_PATH=$QTDIR/lib:$QPEDIR/lib:$LD_LIBRARY_PATH
export QMAKESPEC=$QTDIR/mkspecs/linux-g++
现在我们的准备工作就已经做完了,下面就让我们进入QT的世界吧!
4
百度文库- 让每个人平等地提升自我
带你进入Qt的世界
1.3.1 Hello Qt
我们通过一个简单的例子带你进入Qt的世界。

让我们先一行行的解读下面的代码,然后再编译,运行。

1 #include <QtGui/QApplication>
2 #include <QtGui/QLabel>
3 int main(int argc, char* argv[])
4 {
5 QApplication app(argc, argv);
6 QLabel *label = new QLabel("Hello Qt!");
7 Label->show();
8 return ();
9 }
第1,2行包含的头文件中声明了QApplication和QLabel类。

对于每一个Qt类来说,它们的头文件名称总是与它们的类名相同。

第5行创建了一个QApplication类的对象,来管理应用程序(或许这个地方用进程更合适)资源。

QApplication的构造函数,需要传入argc,argv参数,因为Qt支持命令行参数。

第六行创建了一个QLabel的部件,用来显示“Hello Qt!”。

用Qt和Unix的术语来说,部件就是用户接口中的一个可视化元素。

按钮,菜单,滚动条等都是部件的实例。

当然,一个部件中可以包含另一部件,比如,一个应用程序窗口(也是一个部件)通常就包含了菜单,工具栏,状态栏,和一些其他的部件。

大多数应用程序都以QMainWindow和QDialog作为它们的主窗口。

当然其他的部件也可以作为主窗口,这也是Qt 的灵活之处。

在上面的例子中,QLabel就是应用程序的主窗口。

第7行代码使label变的可见。

部件在创建时,往往都是隐藏的,这样我们可以在让它可见之前设置参数,以免让窗口发生抖动。

第8行通过exec( )函数将应用程序的控制权交给Qt。

代码执行到这里时,程序进入事件循环。

我们这里所说的事件,通常是指点击鼠标,和敲击键盘。

程序会处理由于用户活动产生的事件。

例如,当用户点击一个部件时,会产生鼠标按下和释放两个事件。

在上面的代码中,我们并没有去释放label指针所指向的内存空间,这或许会令许多C++程序员感到不解,当然,您也不必费解,内存释放的事情已经由Qt在main函数结束时帮您完成了,这也是Qt值得称赞的地方,防止了由于部件而产生的内存泄露问题。

OK,现在我们可以来试着编译,运行一下这个程序了。

首先,要先安转好Qt 4.4.3的库(我想你已经完成了吧),并设置好环境变量,然后把的文件复制到hello的目录中。

让我们进入hello的目录,并键入如下命令:
qmake –project
生成一个与平台相关的工程文件,然后再键入:
5
百度文库- 让每个人平等地提升自我
qmake (或者直接qmake)
生成一个指定平台下的makefile
然后就可以用make来编译程序,编译通过后,生成可执行文件hello,通过./hello来运行程序即可。

1.3.2连接信号和槽
这个例子向我们展示了如何处理用户的操作。

这个应用程序有一个按钮,点击按钮后可退出程序,下面是程序代码:
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QPushButton *button = new QPushButton("Quit");
QObject::connect(button, SIGNAL(clicked()),&app, SLOT(quit()));
button->show();
return ();
}
(注:signal and slots parameters must not contain any variable names, only the type.)
当用户有点击动作,或者部件的状态发生变化时,便会触发一个信号。

例如,当用户点击按钮时,会产生一个clicked()信号,当信号发射出去以后,与信号相连接的slot(槽)就会自动执行。

在上面的例子中,我们把按钮的clicked()信号和QApplication对象的quit()槽连接起来,因此点击按钮后,程序就会退出。

在例子中所使用的宏SIGNAL( )和SLOT( )是QT特有的语法,在下面的章节中将会详细介绍到。

图1-1 The Quit application
让我们来编译Qt的应用程序的。

假设你已经创建了一个名为quit文件夹,并且包含了。

进入到quit 文件夹中,执行qmake -project来创建一个工程文件,然后再执行一次qmake,创建makefile,过程如下所示:
qmake –project
qmake (或者qmake
现在你可以执行这个程序的可执行文件了,点击按钮,或者点击空格键,程序就会退出。

6
百度文库- 让每个人平等地提升自我
1.3.3 Laying Out部件
在这个一节中,我们通过一个小例子来展示如何使用layouts(布局器)来管理窗口中部件的几何位置以
及如何使用信号和槽来让不同的部件之间同步。

这个程序用来询问用户的年龄,用户可以通过spinbox或
者slider来输入自己的年龄。

这个程序由这几个部件组成:QSpinBox,QSlider,QWidget。

QWidget是程序的主窗口,QSpinBox,QSlider作为QWidget的子部件。

QWidger的构造函数以及它子类的构造函数都有一个QWidget *的参数来
指明它的父部件。

图1-2 The Age application
源码如下:
1 #include <QApplication>
2 #include <QHBoxLayout>
3 #include <QSlider>
4 #include <QSpinBox>
5 int main(int argc, char **argv)
6{
7 QApplication app(argc, argv);
8 QWidget *window = new QWidget;
9 Window->setWindowTitle(“Enter Your Age”);
10 QSpinBox *spinBox = new QSpinBox;
11 QSlider *slider = new QSlider(Qt::Horizontal);
12 spinBox->setRange(0, 130);
13 slider->setRange(0, 130);
14 QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider,
15SLOT(setValue(int)));
16 QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox,
17SLOT(setValue(int)));
18 spinBox->setValue(35);
19 QHBoxLayout *layout = new QHBoxLayout;
20 layout->addWidget(spinBox);
21 layout->addWidget(slider);
22 window->setLayout(layout);
23 window->show();
24 return ();
25}
第8,9行创建了QWidget部件并设置窗口标题,该部件将作为程序的主窗口。

第10,11行创建了QSpinBox和QSlider,12,13行设置了它们能显示的有效范围。

因为通常来说很少有人的年龄能超过130
岁,所以可以将年龄范围设置在0—130。

我们可以将window传递给QSpinBox,QSlider的构造函数,来
指定QSpinBox,QSlider部件的父部件,但是在这里我们并没有这样做,因为layout已经做了这些并自动
7
百度文库- 让每个人平等地提升自我
设置QSpinBox,QSlider的父部件。

14到17行的代码,两个connect函数确保了spinBox和slider之间的数据同步。

当一个部件的值发生改变时,valueChanged(int)信号被发射,而另一个部件的serValue(int)槽被调用,用来设置更新后的值.
18行设置spinBox的初始值为35。

代码执行到这里时,QSpinBox发射一个valueChanged(int)的信号,并带有一个值为35的参数。

这个参数传递给了QSlider的setValue(int)槽。

QSlider的值被setValue(int)改变后,也会发射一个valueChanged(int)的信号,这个信号同样触发了spin box的槽setValue(int),但由于spin box的值已经是35了,所以它的值不会发生改变,因此这时就不再有信号产生了。

图1-3 槽和信号变迁图
19到22行,我们通过布局管理器来管理spin box和slider。

布局管理器(layout manager)主要用来管理部件的大小及坐标位置。

Qt有三个主要的布局管理器类:
●QHBoxLayout 将部件按照水平从左到右的方向排列。

●QVBoxLayout 将部件按照竖直从上到下的方向排列。

●QGridLayout 将部件放置在一个网格中。

第22行代码,调用了一个setLayout()函数用来在窗口中安装一个布局管理器。

在这个函数返回后,安装了布局管理器的window就成为了QSpinBox,QSlider的父部件,这也就是为什么之前我们不需要显式的指定其父部件的原因。

8
百度文库- 让每个人平等地提升自我
9 图1-4 The Age application的窗口示意图
1.3.4 使用QT的文档
Qt文档对于Qt开发者来说是必不可少的,因为它涵盖了几乎所有的Qt类和它里面的函数。

这本书中所介绍的Qt中的类和函数,只是文档中的一部分,只能起一个抛砖引玉的作用,所以如果你想更深入的了解Qt,那么就要做到对Qt文档非常熟悉才行。

Qt文档以HTML格式存放在Qt的doc/html目录中,你可以通过web浏览器打开,你可以使用Qt Assitant(Qt帮助浏览器)打开。

第二章创建对话框
●对话框
●深入信号和槽
●快速设计对话框
●可变形状的对话框
●动态对话框设计
●动态对话框设计
●内置控件和对话框类
本章将介绍如何使用Qt编写一个对话框应用程序。

对话框提供了良好的人机交互界面,使得用户能够进行输入和选择操作,并能直观的观察到程序的返回结果。

大多数的GUI应用程序都是由一个带菜单项和状态栏的主窗口,和多个对话框组成的。

也可以创建一个只有一个对话框的应用程序,直接对用户的输入做出相应,例如计算器程序。

我们先通过编写代码来实现我们的第一个对话框程序,然后再学习如何使用Qt Designer来创建对话框。

使用Qt Designer能方便快捷的创建对话框,同时也使得维护对话框变得简单了。

对话框
我们的第一个例子是使用C++来创建一个查找对话框。

我们通过创建一个类来实现这个对话框,这个类包含了它自己的信号和槽。

图2-1 查找对话框
源码由两个文件组成:和。

1 #ifndef FINDDIALOG_H
2 #define FINDDIALOG_H
3 #include <QDialog>
4 class QCheckBox;
5 class QLabel;
6 class QLineEdit;
7 class QPushButton;
第1,2 行的预定义宏是为了防止头文件被多次包含。

第三行包含了QDialog类定义的头文件,它的基类是QWidget。

第4到7行声明了我们将在后面使用到的一些类。

这种预声明仅仅是告诉C++编译器所声明的类是存在的,而不用给出类定义的具体细节。

下面我们来定义FindDialog,这个类从QDialog派生
8 class FindDialog : public QDialog
9 {
10 Q_OBJECT
11 public:
12 FindDialog(QWidget *parent = 0);
Q_OBJECT这个宏必须定义在类体的最前面,因为我们在类中定义了信号和槽,所以这个宏是必不可少的。

FindDialog类的构造函数是一个典型的Qt widget类的风格,parent参数指明了它的父部件。

它的默认值是一个空指针,也就是说默认情况下,该对话框没有父部件。

13 signals:
14 void findNext(const QString &str, Qt::CaseSensitivity cs);
15 void findPrevious(const QString &str, Qt::CaseSensitivity cs);
13到第15行声明了两个信号,当用户点击查找按钮时就会触发这两个信号。

当向后搜索有效时,对话框发射findPrevious( )信号,否则就发射findNext( )信号。

signals这个关键字实际也是一个宏,在编译器处理它之前,C++预处理器将它转成标准的C++语言。

Qt::CaseSensitivity是个枚举型,它有两个可取值Qt::CaseSensitive 和Qt::CaseInsensitive。

16 private slots:
17 void findClicked();
18 void enableFindButton(const QString &text);
19 private:
20 QLabel *label;
21 QLineEdit *lineEdit;
22 QCheckBox *caseCheckBox;
23 QCheckBox *backwardCheckBox;
24 QPushButton *findButton;
25 QPushButton *closeButton;
26 };
27 #endif
(注:Signals can never have return types . use void).)
在private区里,我们声明了两个槽。

slots关键字和signals一样,也是一个宏。

对于这些私有变量的声明,我们用的了前面的预声明,之所以可以只使用预声明而不需要把定义这些类的头文件包含近来,是因为这些变量都是指针变量,并且我们并不需要在头文件里访问它们,这样做的好处就是能使编译变得更快些。

头文件的代码已经完成了,下面看看文件吧。

1 #include <QtGui>
2 #include ""
QtGui这个头文件包含了Qt的Gui类的定义。

Qt是由若干个模块组成的,每个模块都有自己的类库。

其中最重要的几个模块是QtCore,QtGui,QtNetwork,QtOpenGL,QtSql,QtSvg,和QtXml,<QtGui>头文件包含了QtCore和QtGui模块中所有类的定义,因此将这个头文件包进来,省去了不少麻烦事。

在中,我们可以通过把<QtGui>头文件包进来而取消include <QDialog>头文件和预声明QCheckBox,QLabel,QLineEdit,和QPushButton类。

但是这样做并不是一个好的建议,因为在大的应用程序中,把一个很大的头文件包含在另一个头文件中是不提倡的。

3 FindDialog::FindDialog(QWidget *parent)
4 : QDialog(parent)
5 {
6 label = new QLabel(tr("Find &what:"));
7 lineEdit = new QLineEdit;
8 label->setBuddy(lineEdit);
9 caseCheckBox = new QCheckBox(tr("Match &case"));
10 backwardCheckBox = new QCheckBox(tr("Search &backward"));
11 findButton = new QPushButton(tr("&Find"));
12 findButton->setDefault(true);
13 findButton->setEnabled(false);
14 closeButton = new QPushButton(tr("Close"));
第4行,将parent参数传给了基类的构造函数。

tr()函数的作用是为了Qt的国际化,将tr()中的文字翻译成另一种语言。

tr()在QObject类中声明,QObject的派生类都可以使用这个函数。

在用户定义的字符串常量前加上tr()是一个好的变成习惯,即使你现在不急着去转译这些文字。

我们在上面的字符串前面加了’&’,这是为了告诉用户它的快捷键操作。

例如,第11行创建了一个查询按钮,你可以选择用鼠标点击,或者通过快捷键Alt+F来触发这个按钮。

’&’也可用于输入焦点的控制:第6行我们创建了一个带有快捷键(Alt+W)的label,第8行将label的关联部件(buddy)设置为line editor。

当label的快捷键被按下时,line edit会接受输入焦点。

第12行,setDefault(true)函数将button的缺省值设为true,这里的缺省值是说当用户按下Enter键时,按钮是否被按下。

第13行将button设为不能用,当一个widget不能用时,通常的方式是让这个widget 变灰并且忽略用户的响应。

15 connect(lineEdit, SIGNAL(textChanged(const QString &)),
16 this, SLOT(enableFindButton(const QString &)));
17 connect(findButton, SIGNAL(clicked()),
18 this, SLOT(findClicked()));
19 connect(closeButton, SIGNAL(clicked()),this, SLOT(close()));
当line edit中的文本被改变时,私有槽enableFindButton(const QString &)就被调用。

当用户点击Find button时,findClicked()槽被调用,点击close button时,对话框就会关闭自己。

close()槽继承于QWidget,调用close(),只是把部件隐藏,而并非真正的销毁它,这点大家要知道。

因为QObject是FindDialog的基类,因此,我们在connect前面可以省略QObject::,而直接调用connect()
函数。

21 QHBoxLayout *topLeftLayout = new QHBoxLayout;
22 topLeftLayout->addWidget(label);
23 topLeftLayout->addWidget(lineEdit);
24 QVBoxLayout *leftLayout = new QVBoxLayout;
25 leftLayout->addLayout(topLeftLayout);
26 leftLayout->addWidget(caseCheckBox);
27 leftLayout->addWidget(backwardCheckBox);
28 QVBoxLayout *rightLayout = new QVBoxLayout;
29 rightLayout->addWidget(findButton);
30 rightLayout->addWidget(closeButton);
31 rightLayout->addStretch();
32 QHBoxLayout *mainLayout = new QHBoxLayout;
33 mainLayout->addLayout(leftLayout);
34 mainLayout->addLayout(rightLayout);
35 setLayout(mainLayout);
下面,我们就使用布局管理器来管理这些部件。

如果你能熟练的使用布局管理器,就能画出看上去很美观的对话框界面。

如下图所示,我们在对话框上使用了两个QHBoxLayout和两个QVBoxLayout。

外面的layout是主layout,负者整个对话框界面部分的管理。

另外三个layout是子layout,负者各个部件布局管理。

右下方的spacer的作用是用来填充layout空白区域,确保两个按钮的位置始终处于layout顶部。

图2-2 Find dialog的布局管理
进行布局管理的这些类并不是我们经常使用的widget,它们继承于QLayout,而QLayout的父类又是QObject。

在使用布局管理器时,对话框中所看到的虚线在程序运行时,并不会出现在用户界面中,这点大家可以放心。

下面这个图显示的就是我们在代码中所使用到的部件的父子关系图:
图2-3 部件之间的父子关系
36 setWindowTitle(tr("Find"));
37 setFixedHeight(sizeHint().height());
38 }
最后,来设置对话框的标题和它的高度。

QWidget::sizeHint()函数返回了对话框的理想尺寸。

下面的代码是对话框槽的定义:
39 void FindDialog::findClicked()
40 {
41 QString text = lineEdit->text();
42 Qt::CaseSensitivity cs =
43 caseCheckBox->isChecked() ? Qt::CaseSensitive
44 : Qt::CaseInsensitive;
45 if (backwardCheckBox->isChecked()) {
46 emit findPrevious(text, cs);
47 } else {
48 emit findNext(text, cs);
49 }
50 }
51 void FindDialog::enableFindButton(const QString &text)
52 {
53 findButton->setEnabled(!());
54 }
在上面代码中,我们可以看到findClicked()槽在被调用时,会发射findPrevius()或者fineNext()的信号。

用来发射信号的emit关键字和Qt中其他关键字一样,会在编译过程中预处理为标准的C++语言。

现在,我们可以创建一个的文件,来测试下我们的代码了:
1 #include <QApplication>
2 #include ""
3 int main(int argc, char *argv[])
4 {
5 QApplication app(argc, argv);
6 FindDialog *dialog = new FindDialog;
7 dialog->show();
8 return ();
9 }
还是使用qmake编译我们的程序,因为代码里面包含了Q_OBJECT的宏,qmake生成的makefile里
面包含了moc的规则,moc也就是Qt的元对象编译器,在后面的章节中会详细介绍到。

为了moc能正确地运行,必须把类的定义与实现分别放在.h和.cpp文件中。

如果你修改了头文件,并在头文件中加入了Q_OBJECT宏,但是没有去更新makefile(此时makefile中并没有moc规则)那么,使用gcc编译时,可能会遇到如下错误:
: In function 'FindDialog::tr(char const*, char const*)':
/usr/lib/qt/src/corelib/global/:1430: undefined reference to
'FindDialog::staticMetaObject'
这时,你可以重新运行qmake,更新makefile,然后再编译代码。

编译完之后,如果一切顺利,没有什么语法错误,就可以运行程序了,你可以验证下所设置的快捷键Alt+W, Alt+C, Alt+B, 和Alt+F,也可以通过tab键来遍历对话框中的部件。

在第三章中,我们还将对这个代码进行修改,并且让findPrevious()和findNext()信号连接多个槽。

深入信号和槽
信号和槽的机制是Qt程序设计的基础。

Qt中的槽跟普通的C++函数没有什么两样,可以是虚函数,可以被重载,可以是声明为public,protected,private也可以像普通成员函数那样被调用,并且槽的参数也可以是任意类型的。

唯一不同的是,槽可以和信号连接,而普通的成员函数却不行,当信号被发射时,槽自动被调用。

信号和槽的连接函数connect(),如下所示:
connect(sender, SIGNAL(signal), receiver, SLOT(slot));
迄今为止,我们所见过的例子是把不同信号和不同的槽连接起来,下面我们看看同一个信号跟多个槽相连。

connect(slider, SIGNAL(valueChanged(int)),
spinBox, SLOT(setValue(int)));
connect(slider, SIGNAL(valueChanged(int)),
this, SLOT(updateStatusBarIndicator(int)));
当信号被发射时,这两个槽依次被调用。

再来看看同一个槽跟多个信号相连:
connect(lcd, SIGNAL(overflow()),
this, SLOT(handleMathError()));
connect(calculator, SIGNAL(divisionByZero()),
this, SLOT(handleMathError()));
同这个槽相连的任何一个信号被发射时,它都会被调用。

信号跟信号相连:
connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SIGNAL(updateRecord(const QString &)));
当前一个信号被发射时,第二个信号也就随之触发了。

除此之外,两个信号连接基本上同信号跟槽连接没什么两样。

解除连接关系:
disconnect(lcd, SIGNAL(overflow()),
this, SLOT(handleMathError()));
这个函数很少用到,因为当一个对象被销毁时,与这个对象相关的那些连接会被Qt自动的解除。

信号和槽之间的连接关系要注意的是,它们要有相同的参数列表,例如:
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
this, SLOT(processReply(int, const QString &)));
但是,当信号的参数个数多于槽的时候,信号中额外的参数会被忽略掉,例如:
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
this, SLOT(checkErrorCode(int)));
当参数类型不匹配时,或者信号或槽并不存在时,在程序运行中,Qt会发出警告。

而且,在connect 函数中,参数名不能出现在信号和槽的声明里,否则Qt也会发出警告。

到目前为止,我们的信号和槽的应用仅仅是限于部件之间,但是,信号和槽的机制是在QObject中实现的,只要是QObject的派生类,都可以使用而并非只限于widget。

如下例:
class Employee : public QObject
{
Q_OBJECT
public:
Employee() { mySalary = 0; }
int salary() const { return mySalary; }
public slots:
void setSalary(int newSalary);
signals:
void salaryChanged(int newSalary);
private:
int mySalary;
};
void Employee::setSalary(int newSalary)
{
if (newSalary != mySalary) {
mySalary = newSalary;
emit salaryChanged(mySalary);
}
}
注意,setSalary()是怎么实现的。

只有当newSalary != mySalary时,信号才被发射,这是为了防止连接陷入死循环中。

快速设计对话框
/********add by su 2009-9-28
用designer创建简单的对话框,例如第1章的quit,请看quit_su.
用DESIGNER做一个按钮,点击则关闭
1 界面保存后得
2 #qmake –project #qmake #make (有错误,没关系) 得或则uic -o
3 自定义类,class my_dialog:public Ui_Dialog,public QDialog 继承2个父类
4 在自定义类的方法中调用setupUi(this);
designer
打开Qt Designer,打开之后,会看到一个模板列表。

点击”Widget”模板,然后确定,这时你会看到一个名为”Untitled”的窗口。

下面我们首先创建一个子部件然后把它放置在form上。

再创建一个label,一个单行编辑框(line editor),一个horizontal spacer,,两个push button。

将这些部件放置在各自的位置上之后,接着来调整窗口的大小。

拖动form的底部,使其大小正好合适。

在窗口的布局上没有必要花费太多时间,因为布局管理器会帮你完成这一切。

图2-6 布局样式图
部件的属性设置:
1.点击text label,设置其文本属性为“&Cell Location”
2.点击line editor,设置其对象名称的属性为“lineEdit”
3.点击第一个按钮,将其对象名称设置为“okButton”,enabled属性设置为“false”,text属性设置
为“OK”,default属性设置为“true”
4.点击第二个按钮。

对象名称设置为“cancelButton”,并将text属性设置为“Cancel”
5.点击背景框,设置对象名称为“GoToCelldialog”并将窗口标题设置为“Go to Cell”。

部件的设置已基本完成了,现在让我们为text label设置一个buddy。

点击Edit|Edit Buddies进入buddies设置模式。

点击label,然后拖动鼠标,将label与line edit连接起来,然后释放鼠标。

图2-7 form的属性设置
下面使用布局管理器管理部件布局:
1.点住shift同时选中label和line editor,然后点击菜单项Form|Lay Out Horizontally
2.点击spacer,选中OK和Cancel按钮,然后点击菜单项From|Lay Out Horizontally
3.点击form背景,不要选中任何条目,然后点击菜单项Form|Lay Out Vertically
4.点击Form|Adjust Size优化form的尺寸
好了,布局已经完成了,但是这个时候你仍然能看到form上的红线,不过不用担心,程序运行的时候,你就不会看到了。

图2-8 form的布局管理图
现在可以来设置对话框的Tab顺序了,选择Edit|Edit菜单项。

你会看到,标有数字的蓝色方框出现在部件上面。

按照顺序,点击每个部件,就可以设置部件的Tab顺序了。

图2-9 tab顺序设置图
对话框界面设置完以后,将其保存在gotocell目录下,名称设置为,然后创建一个文件:
#include <QApplication>
#include <QDialog>
#include ""
int main(int argc, char *argv[])
{。

相关文档
最新文档