## 10.2 Ui_YourFormName.h 文件的组成
我们了解了 uic 工具的使用方法和公用,现在来看看它为我们生成的 C++头文件的组成 是什么样的,里面的“构件”又有哪些功用,这对我们理解后面几节的内容有着重要的作用 。
我们将使用 Qt Designer 创建一个界面文件,名为 calculatorform.ui,这个程序主要 是完成简单的加法计算功能。该界面的元素组合如图 10-1 所示。
![](https://box.kancloud.cn/2016-01-22_56a1a1574ce42.png)
图 10-1 使用 Qt Designer 制作的界面
怎样做到在不使用 qmake 的情况下,就可以产生对应的头文件呢,我们遵循上一节介绍 的方法,在 Qt 的命令行下面输入如下命令:
```
uic –o ui_calculatorform.h calculatorform.ui
```
小贴士:再次提醒,以 Windows XP 操作系统为例,进入 Qt 命令行的方法是:依次点击【开始】->【所有程序】->【Qt SDK by Nokia v2009.03 (open source)】->【Qt Command Prompt】。然后切换到你的.ui 文件所在的目录,执行上述命令即可。
以下是据此生成的 ui_calculatorform.h 文件的完整内容,我将分段向大家讲解。
```
/********************************************************************************
** Form generated from reading ui file 'calculatorform.ui'
**
** Created: Sun Sep 6 22:34:26 2009
** by: Qt User Interface Compiler version 4.5.2
**
** WARNING! All changes made in this file will be lost when recompiling ui file!
********************************************************************************/
```
这一段代码是 uic 工具自动生成的注释内容,它记录了该 C++头文件对应的原始.ui 文件的名字以及产生的时间和使用的 uic 的版本。最后一行提示内容很重要,它明确的告诉我们,不要手动修改该文件内容,因为在下次运行 qmake 或者 uic 时,它们会被覆盖掉。所以,我们如果需要对文件内容做修改,那么到 Qt Designer 中修改界面元素就行了,uic 会把所 有的改动反映出来。
```
#ifndef UI_CALCULATORFORM_H
#define UI_CALCULATORFORM_H
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QGridLayout>
#include <QtGui/QHeaderView>
#include <QtGui/QLabel>
#include <QtGui/QSpacerItem>
#include <QtGui/QSpinBox>
#include <QtGui/QVBoxLayout>
#include <QtGui/QWidget>
```
上面这段的开头两句加上该文件结尾的 #endif // UI_CALCULATORFORM_H 这句构成了完整的防止头文件重复定义的卫哨,这是很好的编程规范,我们在自己书写代码时,也要遵循 这种严谨的做法。
后面的几句加入了程序中用到的窗口部件以及变量的头文件 。请大家注意它们的用法也 是非常规范的,正是许多 C++大师所提倡的“用到什么就包含什么,不用的就不包含 ”的做 法的应用典范。笔者发现有很多的朋友不论什么情况,都喜欢加入一句 #include <QtGui>或 者#include <QtCore>,这固然省事,因为它们包含了这两个模块下的所有子模块的定义 ,但 是这样一来,就降低了程序的编译速度,使得性能下降。
```
QT_BEGIN_NAMESPACE
class Ui_CalculatorForm
{
public:
QGridLayout *gridLayout;
QSpacerItem *spacerItem;
QLabel *label_3_2;
QVBoxLayout *vboxLayout;
QLabel *label_2_2_2;
QLabel *outputWidget;
QSpacerItem *spacerItem1;
QVBoxLayout *vboxLayout1;
QLabel *label_2;
QSpinBox *inputSpinBox2;
QLabel *label_3;
QVBoxLayout *vboxLayout2;
QLabel *label;
QSpinBox *inputSpinBox1;
```
上面这段代码中,首先用 QT_BEGIN_NAMESPACE 宏表示开始进入名字空间。然后定义了一个名为 Ui_CalculatorForm 的类,它实际上是界面的实体类,界面上的所有元素都被定义 为相应的窗口部件的实例,并且它们一定是被定义为 public,即公有的成员,这将使得后面的 Ui 名字空间内的派生类能够继承它们。
```
void setupUi(QWidget *CalculatorForm)
{
if (CalculatorForm->objectName().isEmpty())
CalculatorForm->setObjectName(QString::fromUtf8("CalculatorForm"));
CalculatorForm->resize(400, 300);
QSizePolicy sizePolicy(static_cast<QSizePolicy::Policy>(5),
static_cast<QSizePolicy::Policy>(5));
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(CalculatorForm->sizePolicy().hasHeightForWidth());
CalculatorForm->setSizePolicy(sizePolicy);
gridLayout = new QGridLayout(CalculatorForm);
#ifndef Q_OS_MAC
gridLayout->setSpacing(6);
#endif
#ifndef Q_OS_MAC
gridLayout->setMargin(9);
#endif
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
gridLayout->setObjectName(QString::fromUtf8(""));
spacerItem = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
gridLayout->addItem(spacerItem, 0, 6, 1, 1);
label_3_2 = new QLabel(CalculatorForm);
label_3_2->setObjectName(QString::fromUtf8("label_3_2"));
label_3_2->setGeometry(QRect(169, 9, 20, 52));
label_3_2->setAlignment(Qt::AlignCenter);
gridLayout->addWidget(label_3_2, 0, 4, 1, 1);
vboxLayout = new QVBoxLayout();
#ifndef Q_OS_MAC
vboxLayout->setSpacing(6);
#endif
vboxLayout->setMargin(1);
vboxLayout->setObjectName(QString::fromUtf8("vboxLayout"));
vboxLayout->setObjectName(QString::fromUtf8(""));
label_2_2_2 = new QLabel(CalculatorForm);
label_2_2_2->setObjectName(QString::fromUtf8("label_2_2_2"));
label_2_2_2->setGeometry(QRect(1, 1, 36, 17));
vboxLayout->addWidget(label_2_2_2);
outputWidget = new QLabel(CalculatorForm);
outputWidget->setObjectName(QString::fromUtf8("outputWidget"));
outputWidget->setGeometry(QRect(1, 24, 36, 27));
outputWidget->setFrameShape(QFrame::Box);
outputWidget->setFrameShadow(QFrame::Sunken);
outputWidget->setAlignment(Qt::AlignAbsolute|Qt::AlignBottom|Qt::AlignCenter|Qt::AlignHCenter
|Qt::AlignHorizontal_Mask|Qt::AlignJustify|Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::
AlignTop|Qt::AlignTrailing|Qt::AlignVCenter|Qt::AlignVertical_Mask);
vboxLayout->addWidget(outputWidget);
gridLayout->addLayout(vboxLayout, 0, 5, 1, 1);
spacerItem1 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
gridLayout->addItem(spacerItem1, 1, 2, 1, 1);
vboxLayout1 = new QVBoxLayout();
#ifndef Q_OS_MAC
vboxLayout1->setSpacing(6);
#endif
vboxLayout1->setMargin(1);
vboxLayout1->setObjectName(QString::fromUtf8("vboxLayout1"));
vboxLayout1->setObjectName(QString::fromUtf8(""));
label_2 = new QLabel(CalculatorForm);
label_2->setObjectName(QString::fromUtf8("label_2"));
label_2->setGeometry(QRect(1, 1, 46, 19));
vboxLayout1->addWidget(label_2);
inputSpinBox2 = new QSpinBox(CalculatorForm);
inputSpinBox2->setObjectName(QString::fromUtf8("inputSpinBox2"));
inputSpinBox2->setGeometry(QRect(1, 26, 46, 25));
vboxLayout1->addWidget(inputSpinBox2);
gridLayout->addLayout(vboxLayout1, 0, 3, 1, 1);
label_3 = new QLabel(CalculatorForm);
label_3->setObjectName(QString::fromUtf8("label_3"));
label_3->setGeometry(QRect(63, 9, 20, 52));
label_3->setAlignment(Qt::AlignCenter);
gridLayout->addWidget(label_3, 0, 1, 1, 1);
vboxLayout2 = new QVBoxLayout();
#ifndef Q_OS_MAC
vboxLayout2->setSpacing(6);
#endif
vboxLayout2->setMargin(1);
vboxLayout2->setObjectName(QString::fromUtf8("vboxLayout2"));
vboxLayout2->setObjectName(QString::fromUtf8(""));
label = new QLabel(CalculatorForm);
label->setObjectName(QString::fromUtf8("label"));
label->setGeometry(QRect(1, 1, 46, 19));
vboxLayout2->addWidget(label);
inputSpinBox1 = new QSpinBox(CalculatorForm);
inputSpinBox1->setObjectName(QString::fromUtf8("inputSpinBox1"));
inputSpinBox1->setGeometry(QRect(1, 26, 46, 25));
vboxLayout2->addWidget(inputSpinBox1);
gridLayout->addLayout(vboxLayout2, 0, 0, 1, 1);
retranslateUi(CalculatorForm);
QMetaObject::connectSlotsByName(CalculatorForm);
} // setupUi
```
上面这段代码是界面实体类的公有方法 setupUi()的内容。这是最为重要的一个成员函数,它完成了整个界面的构造和布局,代码的内容比较简单,遵循了我们前面反复讲到的使 用 Qt 编程的基本步骤,即先声明要使用到的窗口部件,然后实例化它们,再为它们设置属 性和方法。
QMetaObject::connectSlotsByName(CalculatorForm);这一句是需要重点说明的,因为 它实现了 CalculatorForm 界面实体类中的信号与槽机制。这个方法的原型是:
```
void QMetaObject::connectSlotsByName ( QObject * object ) [static]
```
它是 QMetaObject 类的静态方法,作用是递归搜索 object 对象及子对象,然后将其中相匹配的信号与槽连接起来。所谓相匹配的信号与槽,就是要求槽函数的书写形式如下所示:
```
void on_<object name>_<signal name>(<signal parameters>);
```
从编程人员的角度来看,只要将槽函数遵循上面的书写形式 ,就能够实现信号和槽的自动关联,而无需手写代码显式的完成。
再举个例子,假设我们的界面实体类中含有一个子对象,它的类型是 QPushButton,它 的 objectName 属性被设置为 btn1。那么为了使槽函数与信号 clicked()能够自动关联,我们 必须将槽函数写成如下形式:
```
void on_button1_clicked();
```
小贴士:QMetaObject 类是 Qt 元对象系统(Meta-Object System)的组成部分,是实现信号/槽机制、运行时类型信息以及 Qt 属性系统的基础。在一个应用程序中所有的 QObject 子类 都会创建一个属于自己的单独的 QMetaObject 的实例,并且这个实例存储了该子类的所有元 对象信息。这些通常包括类名(class name)、超类名(superclass name)、属性信息(properties)、信号与槽(signals and slots)等。
关于 Qt 的元对象系统,我们会在后面的第 13 章作详细介绍。
在后面我们会介绍编译时处理.ui 文件的 3 种方法:直接使用法、单继承法和多继承法。 无论使用它们中的哪一种,都要显式的调用 setupUi()这个方法来完成界面元素的构造和布 局,而它的参数就是你自定义的窗体类,这一点请大家在阅读时注意。
```
void retranslateUi(QWidget *CalculatorForm)
{
CalculatorForm->setWindowTitle(QApplication::translate("CalculatorForm",
"Calculator Form", 0, QApplication::UnicodeUTF8));
label_3_2->setText(QApplication::translate("CalculatorForm", "=", 0,
QApplication::UnicodeUTF8));
label_2_2_2->setText(QApplication::translate("CalculatorForm", "Output", 0,
QApplication::UnicodeUTF8));
outputWidget->setText(QApplication::translate("CalculatorForm", "0", 0,
QApplication::UnicodeUTF8));
label_2->setText(QApplication::translate("CalculatorForm", "Input 2", 0,
QApplication::UnicodeUTF8));
label_3->setText(QApplication::translate("CalculatorForm", "+", 0,
QApplication::UnicodeUTF8));
label->setText(QApplication::translate("CalculatorForm", "Input 1", 0,
QApplication::UnicodeUTF8));
Q_UNUSED(CalculatorForm);
} // retranslateUi
```
以上这段是 retranslateUi 方法的定义,它使得应用程序具备了支持国际化的能力 。其
中调用了 translate()方法,它是在 Qt 4.5 以后新引入的。
```
namespace Ui {
class CalculatorForm: public Ui_CalculatorForm {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_CALCULATORFORM_H
```
上面这段代码定义了名字空间 Ui,在其内部声明了一个名为 CalculatorForm 的类,它单公有继承自界面实体类 Ui_CalculatorForm,这就使得它继承了界面实体类的所有公有成 员。声明名字空间的用意是防止混淆命名。
注意,这个类的名字是与你的.ui 文件中 Form 的 objectName 的属性值相一致的。在后面的章节里,我们都要与这个类打交道,而不与界面实体类 Ui_CalculatorForm 发生联系,这样做就使得应用程序的界面设计与代码尽可能的分离开来,是现代编程思想的体现。
- 第 1 章 走近 Qt
- 1.1 Qt 简介
- 1.2 Qt 纪事概览
- 1.3 Qt 套件的组成(以 Qt4.5 为准)
- 1.4 Qt 的授权
- 1.5 Qt 的产品
- 1.6 Qt 的服务与支持
- 1.7 Qt 的最新进展
- 1.8为什么选择 Qt
- 1.9 问题与解答
- 1.10 总结与提高
- 第 2 章 Qt 的安装与配置
- 2.1 获取 Qt
- 2.2 协议说明
- 2.3 安装 Qt
- 2.4 配置 Qt4 环境
- 2.5 问题与解答
- 2.6 总结与提高
- 第 3 章 Qt 编程基础
- 3.1 标准 C++精讲
- 3.2 Windows 编程基础
- 3.3 Linux 编程基础
- 3.4 Mac 编程基础
- 3.5 问题与解答
- 3.6 总结与提高
- 第 4 章 Qt 4 集成开发环境
- 4.1 常见的 Qt IDE
- 4.2 Qt Creator
- 4.3 Eclipse
- 4.5 问题与解答
- 4.6 总结与提高
- 第 5 章 使用 Qt 基本 GUI 工具
- 5.1 使用 Qt Designer 进行 GUI 设计
- 5.2 使用 Qt Assistant 获取在线文档与帮助
- 5.3 使用 Qt Demo 学习 Qt 应用程序开发
- 5.4 问题与解答
- 5.5 总结与提高
- 第 6 章 Qt 4 程序开发方法和流程
- 6.1 开发方法
- 6.2 Hello Qt
- 6.3 几个重要的知识点
- 6.4 问题与解答
- 6.5 总结与提高
- 第 7 章 对话框
- 7.1 QDialog 类
- 7.2 子类化 QDialog
- 7.3 快速设计对话框
- 7.4 常见内建(built in)对话框的使用
- 7.5 模态对话框与非模态对话框
- 7.6 问题与解答
- 7.7 总结与提高
- 第 8 章 主窗口
- 8.1 主窗口框架
- 8.2 创建主窗口的方法和流程
- 8.3 代码创建主窗口
- 8.4 使用 Qt Designer 创建主窗口
- 8.5 中心窗口部件专题
- 8.6 Qt4 资源系统专题
- 8.7 锚接窗口
- 8.8 多文档
- 8.9 问题与解答
- 8.10 总结与提高
- 第 9 章 Qt 样式表与应用程序观感
- 9.1 应用程序的观感
- 9.2 QStyle 类的使用
- 9.3 样式表概述
- 9.4 使用样式表
- 9.5 问题与解答
- 9.6 总结与提高
- 第 10 章 在程序中使用.ui 文件
- 10.1 uic 的使用
- 10.2 Ui_YourFormName.h 文件的组成
- 10.3 编译时加入处理.ui 文件的方法
- 10.4 运行时加入处理.ui 文件的方法
- 10.5 信号与槽的自动连接
- 10.6 问题与解答
- 10.7 总结与提高 本章主要讲解了以下内容:
- 第 11 章 布局管理
- 11.1 基本概念和方法
- 11.2在 Qt Designer 中使用布局
- 11.3 基本布局实践
- 11.4 堆栈布局
- 11.5 分裂器布局
- 11.6 自定义布局管理器
- 11.7 布局管理经验总结
- 11.8 问题与解答
- 11.9 总结与提高
- 第 12 章 使用 Qt Creator
- 12.1 Qt Creator 概览
- 12.2 Qt Creator 的组成
- 12.3 快捷键和常用技巧
- 12.4 Qt Creator 构建系统的设置
- 12.5 处理项目间依赖关系( Dependencies )
- 12.6 Qt 多版本共存时的管理
- 12.7 使用定位器在代码间快速导航
- 12.8 如何创建一个项目
- 12.9 实例讲解
- 12.10 使用 Qt Creator 调试程序
- 12.11 问题与解答
- 12.12 总结与提高
- 第 13 章 Qt 核心机制与原理
- 13.1 Qt 对标准 C++的扩展
- 13.2 信号与槽
- 13.3 元对象系统
- 13.4 Qt 的架构
- 13.5 Qt 的事件模型
- 13.6 构建 Qt 应用程序
- 13.7 总结与提高
- 附录 A qmake 使用指南
- A.1 qmake 简介
- A.2 使用 qmake
- 附录 B make 命令
- B.1 命令解释
- B.2 使用 make 自动构建
- 附录 C Qt 资源
- C.1Qt 官方资源
- C.2 Qt 开发社区