## 10.2 Ui_YourFormName.h 文件的組成
我們了解了 uic 工具的使用方法和公用,現在來看看它為我們生成的 C++頭文件的組成 是什么樣的,里面的“構件”又有哪些功用,這對我們理解后面幾節的內容有著重要的作用 。
我們將使用 Qt Designer 創建一個界面文件,名為 calculatorform.ui,這個程序主要 是完成簡單的加法計算功能。該界面的元素組合如圖 10-1 所示。

圖 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 開發社區