| 
 
| Qt 设计器(Qt Designer)内容总结 1、概述
 Qt 允许程序员不通过任何设计工具,以纯粹的 C++代码来设计一个程序。但是更多的
 程序员更加习惯于在一个可视化的环境中来设计程序,尤其是在界面设计的时候。这是因为
 这种设计方式更加符合人类思考的习惯,也比书写代码要快速的多。
 Qt 也提供了这样一个可视化的界面设计工具:Qt 设计器(Qt Designer)。其开始界面
 如上图所示。Qt 设计器可以用来开发一个应用程序全部或者部分的界面组件。以 Qt 设计器
 生成的界面组件最终被变成 C++代码,因此 Qt 设计器可以被用在一个传统的工具链中,并
 且它是编译器无关的。
 在不同的平台上启动 Qt Designer 的方式有一定差别。在 Windows 环境下你可以在“开
 始->程序->Qt”这个组件中找到 Qt Designer 的图标并点击;在 Unix 环境下,在命令行模式
 下输入命令: “designer”;在 Mac Os 下,在 X    Finder 下双击 Designer 图标。
 默认情况下,Qt Designer 的用户界面是由几个顶级的窗口共同组成的。如果你更习惯
 于一个 MDI-style 的界面(由一个顶级窗口和几个子窗口组成的界面),可以在菜单 Edit->User
 Interface Mode 中选择 Docked Window 来切换界面。上图显示的就是 MDI-style 的界面风格。
 2、开始学习
 在这个小节中,我们将使用 Qt Designer 来生成一个对话框: Go-to-cell。对话框如下图
 所示。
 不管我们是使用 Qt Designer 还是编码来实现一个对话框,都包括以下相同的步骤:
 1)、创建并初始化子窗口部件。
 2)、将子窗口部件放置到布局当中。
 3)、对 Tab 的顺序进行设置。
 4)、放置信号和槽的连接。
 5)、完成对话框的通用槽的功能。
 现在开始工作。首先在 Qt Designer 的菜单中选择“File->New Form”。程序将弹出一
 个窗口如下:
 可以看到在窗口左上方有一个“templates\forms”的菜单,下面有四个可供选择的模板。
 第一个和第二个都是对话框,区别在于对话框中按钮的位置不同。第三个是主窗口,第四
 个是窗口部件。本例中我们需要选择第四个选项(Widget)。 现在你应该可以看到 Qt Designer
 为你生成了一个窗口,标题栏是“Untitled”(也许你觉得第一个模板更加适合我们的例子,
 不过,在这里,我们将手动添加“OK”和“Cancel”这两个按钮)。
 我们按照上面讲过的顺序来设计这个窗口。首先需要生成子窗口部件并将它们放置
 在工作台上。在 Qt Designer 工作界面的左侧,我们可以看到很多程序设计经常用到的窗口
 部件。如果你需要它们中的那一个,用鼠标把它拖到工作台上就可以了。我们在菜单“Display
 Widgets”中选择一个“Label”,在菜单“Input Widgets”中选择一个“Line Edit”,在菜单
 “Spacers”中选择一个“Horizontal Spacer”(这个空白组件在最终形成的窗口中是不可见的,
 在 Qt Designer 中,空白组件的样子就像是一个蓝色的弹簧),在菜单“Buttons”中选择两个
 “Push Button”。按照下图的位置,将它们摆放起来。
 你可以看到,我们的工作界面显的太大了一些,可以用鼠标拉住边框让它改变大小,
 直到你满意为止。一个类似下图的组件是不是已经出现了?记住不要花费太多的时间来摆放
 这些窗口部件的位置,只要大概类似就可以了,因为他们并不是不可调整的。Qt 的布局管
 理器将会对他们的位置和大小自动进行一些优化。
 现在我们已经创建了这些子窗口部件,并把他们放置在了合适的位置,接下来要做
 的就是初始化他们。这需要设定这些子窗口的属性。在 Qt Designer 工作界面的右侧也同样
 有一些窗口,这些就是属性窗口。 可以在这些窗口中找到所有部件需要设置的属性,并更改
 它们,就可以达到我们的目的了。
 1)、点击 TextLabel,确认它的“objectName”属性是“label”,然后将它的“text”属
 性设置为“&Cell Location”。
 2)、点击 line editor (窗口中的空白编辑框),确认它的“objectName”属性是“lineEdit”。
 3)、点击第一个按钮(左侧),将其“objectName”属性设置为“OKButton”,“enable”
 属性设置为“false”,“text”属性设置为“OK”,“default”属性设置为“true”。
 4)、点击第二个按钮(右侧),将其“objectName”属性设置为“cancelButton”,“text”
 属性设置为“Cancel”。
 5)、点击工作平台的背景,这样我们可以选择整个的界面。这也是一个窗口,也拥有
 自己的属性。我们把它的“objectName”属性设置为“GoToCellDialog”,“windowtTitle”属
 性设置为“Go to Cell”。
 完成后的 Form 变成了下图的形式:
 接下来我们给 Label 设置一个伙伴(buddy),在这个例子中, Label 的伙伴当然是后面
 的字符编辑框 line editor。在 Qt Designer 的菜单中进行选择:Edit->Edit Buddies。这样我们
 进入 Buddy 模式,可以设置子窗口的伙伴了。点击 Label,Label 将会变成红色的,同时出
 现一条线,将这条线拖拽到后面的 line editor 上,然后松开。这时两个窗口都将变成红色的,
 中间有一条红线相连。移动鼠标到别处并点击,窗口将变成蓝色的。这说明我们已经设置成
 功了(如果设置错误,则可以用鼠标在连接窗口的线条上点击,这时相连的窗口又会变成红
 色的,此时按 Delete 键就可以取消设置)。选择:Edit->Edit Widget,可以退出这个模式,回
 到主菜单中。如下图所示:
 接下来我们对工作台上的各个子窗口进行布局:
 1)、 点击标签“Cell Location”,按住 Shift 键,再点击后面的字符编辑框“line editor”,
 这样它们两个窗口被同时选中。选择菜单:Form->Lay Out Horizontally。这样这两个窗口将
 被一个红色边框的矩形包围。
 2)点击空白子窗口“Spacer”,按住 Shift 键,再点击后面的两个按钮,同时选定这三
 个窗口,然后选择菜单:Form->Lay Out Horizontally。这样这三个窗口将被一个红色边框的
 矩形包围。
 3)、点击工作平台的背景,取消任何已经选择的组件,然后选择:Form->Lay Out
 Vertically。这样我们可以将第 1 步和第 2 步所生成的两个水平布局进行垂直布局。
 4)、选择菜单:Form->Adjust Size。这样我们可以调整主窗口的大小。最后效果如下
 图(图中的红线在程序最终生成的时候不会被显示):
 然后我们对 Tab 的顺序进行设置。选择菜单:Edit->Edit Tab Order。一个带有数字的
 蓝色矩形会显示在每一个窗口部件上(由于我们将 Label 和 line editor 设置为 buddy,这样
 它们在指定 Tab 的时候被视为一个组件)。点击这些带数字的矩形可以调整到你想要的顺序
 上,然后选择:Edit->Edit Widgets 离开这个模式。
 现在我们的对话框的外形已经完成了。选择菜单:Form->Preview。这样你可以预览我
 们设计的窗口。可以反复按下 Tab 键来验证顺序是否和我们设置的一致。点击顶部的关闭按
 钮就可以关闭这个预览窗口。
 所有的界面设计工作已经完成了,现在我们要做的就是保存下来。选择菜单: File->Save
 Form As:。建立一个名为“gotocell”的文件夹,将这个界面保存为名称为“gotocelldialog.ui”
 的文件中,放置到新建的文件夹中。
 下面我们试着显示这个对话框。在文件夹“gotocell”中建立一个文件 main.cpp。在 cpp
 文件中编写代码如下:
 #include <QApplication>
 #include <QDialog>
 #include "ui_gotocelldialog.h"
 int main (int argc, char *argv [])
 {
 QApplication app (argc, argv);
 Ui::GoToCellDialog    ui;
 QDialog *dialog = new QDialog;
 ui.setupUi (dialog);
 dialog->show ();
 return app. exec ();
 }
 现在我们运行 qmake 工具来生成一个工程文件 (.pro)和一个 makefile (qmake –project;
 qmake gotocell.pro)。qmake 是一个足够聪明的工具,它可以侦测到当前文件夹中的用户界
 面文件(在本例中就是我们刚才保存的 gotocelldialog.ui),并且自动生成合适的 makefile
 规则来调用 uic(uic 就是 Qt 的用户界面编译器)。Uic 工具将把文件 gotocelldialog.ui 的内
 容转换成 C++代码,写入自动生成的头文件“ui_gotocelldialog.h”中。
 生成的头文件“ui_gotocelldialog.h”包括了对类 Ui::GoToCellDialog 的定义。这是一
 个和 gotocelldialog.ui 文件内容相同的定义,只不过它是用 C++表示的。这个类声明了存储
 各个子窗口和布局的成员变量,还包括一个 setupUi()的成员函数,用来初始化程序窗口。生
 成的类就像下面所显示的一样:
 class Ui::GoToCellDialog
 {
 public:
 QLabel *label;
 QLineEdit *lineEdit;
 QSpacerItem *spacerItem;
 QPushButton *okButton;
 QPushButton *cancelButton;
 ...
 void setupUi (QWidget *widget) {
 ...
 }
 };
 这个自动生成的类并没有继承任何 Qt 的类。当我们在 main.cpp 中使用这个界面的时
 候,我们创建一个 QDialog 并把它传递给函数 setupUi()。
 现在可以编译并运行这个程序了。程序界面已经可以开始工作了,但是你会发现一些
 问题——界面的功能并没有完全实现:
 1)、按钮“OK”总是不可见的。
 2)、按钮“Cancel”虽然可以显示,但它什么也不能做。
 3)、字符编辑框接受任何字符,而不是像我们期望的那样只接受合法的数字。
 显然我们应该通过编辑一些代码来使对话框函数正确地工作。最干净利落的方法是类
 继承。我们创建一个新的类,这个类同时继承 QDialog(程序中创建的,被传递给函数
 setupUi())和 Ui::GoToCellDialog,并完成这些未实现的功能(这也验证了一条名言:任何
 软件的问题都可以通过添加一个间接的层来解决)。对于这样的一个类,我们的命名习惯是:
 把 uic 生成的类去掉前缀“Ui::”作为我们的类名称。本例中,这个类叫 GoToCellDialog。
 创建一个头文件 gotocelldialog.h,在里面编辑代码如下:
 #ifndef GOTOCELLDIALOG_H
 #define GOTOCELLDIALOG_H
 #include <QDialog>
 #include "ui_gotocelldialog.h"
 class GoToCellDialog: public QDialog, public Ui::GoToCellDialog
 {
 Q_OBJECT
 public:
 GoToCellDialog (QWidget *parent = 0);
 private slots:
 void on_lineEdit_textChanged ();
 };
 #endif
 有了头文件,我们还需要源文件。再创建一个 gotocelldialog.cpp,编辑代码如下:
 #include <QtGui>
 #include "gotocelldialog.h"
 GoToCellDialog::GoToCellDialog (QWidget *parent)
 : QDialog (parent)
 {
 setupUi (this);
 QRegExp regExp ("[A-Za-z] [1-9] [0-9] {0, 2}");
 lineEdit->setValidator (new QRegExpValidator (regExp, this));
 connect (okButton, SIGNAL (clicked ()), this, SLOT (accept ()));
 connect (cancelButton, SIGNAL (clicked ()), this, SLOT (reject ()));
 }
 void GoToCellDialog::on_lineEdit_textChanged ()
 {
 okButton->setEnabled (lineEdit->hasAcceptableInput ());
 }
 在构造函数中,我们调用了 setupUi()来初始化工作平台。由于采用了多重继承,这使
 得我们可以直接访问类 Ui::GoToCellDialog 的成员变量。在用户界面生成之后,函数 setupUi()
 将会把任何遵循命名规则:on_objectName_signalName()而命名的槽和“objectName”中的
 信号 signalName()连接起来。在这个例子中,这意味着函数 setupUi()将会建立如下的连接:
 connect (lineEdit, SIGNAL (textChanged (const QString &)),
 this, SLOT (on_lineEdit_textChanged ()));
 同样的,在构造函数中,我们设置了一个验证器(validator)来限制输入的范围。Qt
 有三个内置的验证器,他们分别是:QIntValidator,QDoubleValidator 和 QRegExpvalidator。
 这里我们使用了一个 QRegExpValidator 验证器,其规则表达式为"[A-Za-z] [1-9] [0-9] {0, 2}"。
 它表示:允许一个大写或者小写的字母,这个字母后面紧跟着一个取值范围为[1-9]的数字,
 再紧跟位数取值范围为[0-2] (即不可超过 100)的数字,这个数字每一位的取值范围是[0-9]。
 我们把一个 this 指针传递给验证器 QRegExpValidator 的构造函数,这样我们使它成为
 对象 GoToCellDialog 的一个子对象。通过这样,我们就不必在后面花费心思考虑对于这个
 QRegExpValidator 的删除——它会在它的父对象被删除时自动销毁。
 Qt 的父子机制是在 QObject 中实现的。当我们从父对象中产生一个子对象时(可以是
 一个 widget,一个 validator 或者任何形式),父对象就把这个对象加入到它的子对象链表中。
 当父对象被删除时,它会遍历这个链表并销毁每一个子对象。这些子对象然后再继续销毁属
 于它们的子对象。如此的循环,直到没有对象剩下为止。
 这种机制极大地简化了程序的内存管理任务,减少了内存泄露的危险。当我们删除父
 窗口时,子窗口不光从内存中消失,从屏幕上也会消失。
 在构造函数的最后,我们将按钮 OK 和 QDialog 的槽 accept()相连;将按钮 Cancel 和
 槽 reject()相连。这两个槽都会关闭窗口,但是 accept()将对话框的结果传给 QDialog::Accepted
 (实际上是整数 1);而 reject()则将对话框的结果传给 QDialog::Rejected (实际上是整数 0) 。
 当我们使用这个对话框的时候,我们可以查看它的返回值来确认用户是否按下了按钮 OK;
 程序运行是否正确。
 槽 on_lineEdit_textChanged()的作用是:根据字符编辑框中的内容是否合法来决定按钮
 OK 可见或不可见。函数 QLineEdit::hasAcceptableInput()使用了我们在构造函数中看到过的
 验证器。
 以上我们已经完成了对话框的所有工作。现在我们重写 main.cpp:
 #include <QApplication>
 #include "gotocelldialog.h"
 int main (int argc, char *argv [])
 {
 QApplication app (argc, argv);
 GoToCellDialog *dialog = new GoToCellDialog;
 dialog->show ();
 return app.exec ();
 }
 重新编译并执行程序。我们的程序可以正常工作了。
 使用 Qt Designer 的好处之一是把程序员从必须修改他们的代码来适应界面的改变这
 个烦恼中解脱出来。如果你使用纯粹的代码来编写界面,改变界面设计将耗费大量的时间。
 应用 Qt Designer 将不会有任何时间上的损失: uic 工具会根据界面的改变自动更新代码。对
 话框用户界面被保存为  .ui  文件的格式(基于 XML 的文件格式), 通过派生 uic 工具生成的
 类,这种普遍的泛函性得到了实现。
 
 
 | 
 |