Qt .ui檔案的使用

2020-07-16 10:04:48
.ui 檔案其實就一個標準 XML 格式的文字檔案(感興趣的讀者可以用記事本開啟看看),需要通過 uic 工具將其轉換為專案裡可用的 ui_*.h 標頭檔案, 這個標頭檔案裡才是真正可用的 C++ 程式碼。

接下來我們以《Qt Designer的簡單使用》中生成的 hello.ui 為例來講解如何把 .ui 檔案轉換成 C++ 程式碼,以及如何使用 .ui 檔案。

開啟 Qt 命令列工具,進入 D:QtDemo 資料夾:

cd /d D:QtDemo

執行 uic 命令:

uic hello.ui -o ui_hello.h

檢視該標頭檔案程式碼,內容如下:
/********************************************************************************
** Form generated from reading UI file 'hello.ui'
**
** Created by: Qt User Interface Compiler version 5.9.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/

#ifndef UI_HELLO_H
#define UI_HELLO_H

#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_Form
{
public:
    QLabel *label;

    void setupUi(QWidget *Form)
    {
        if (Form->objectName().isEmpty())
            Form->setObjectName(QStringLiteral("Form"));
        Form->resize(427, 244);
        label = new QLabel(Form);
        label->setObjectName(QStringLiteral("label"));
        label->setGeometry(QRect(10, 10, 200, 40));

        retranslateUi(Form);

        QMetaObject::connectSlotsByName(Form);
    } // setupUi

    void retranslateUi(QWidget *Form)
    {
        Form->setWindowTitle(QApplication::translate("Form", "Form", Q_NULLPTR));
        label->setText(QApplication::translate("Form", "C350257255350250200344270255346226207347275221", Q_NULLPTR));
    } // retranslateUi

};

namespace Ui {
    class Form: public Ui_Form {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_HELLO_H
程式碼開頭的註釋提醒開發者不要手動修改該標頭檔案,因為 uic 工具下次自動生成 .h 檔案時,會把舊的程式碼全清掉,然後生成新的程式碼內容。

QT_BEGIN_NAMESPACE 和 QT_END_NAMESPACE 這兩個宏標示中間的程式碼是包含在命名空間裡的,就是一個提示作用,沒有實際意義。

第一個類是全域性範圍定義的 Ui_Form 類,裡面首先定義了一個 label 指標,注意這個指標名稱就是之前設計師裡顯示的 objectName。

接著定義了一個 setupUi 函數,這個是最關鍵的生成圖形介面的函數,它接收一個 QWidget 物件的指標,然後為這個 QWidget 物件設定視窗介面和控制元件。

還有一個 retranslateUi 函數,是專門用於支援多國語言翻譯的,主視窗和標籤控制元件的字串都在這重新翻譯一下,如果有多國語言支援的翻譯檔案,介面的多國語言顯示就通過該函數實現。

這兩個函數細節就不講解了,以後還會遇到,而且它們都是 uic 自動生成的,不需要我們手動編寫或修改,不用太擔心細節,學會用這個標頭檔案就可以了。

接下來定義了一個叫 Ui 的命名空間,空間裡定義了一個類 Form ,簡單地從 Ui_Form 類繼承一下,並沒有新增額外的程式碼。使用 Ui 命名空間的好處就是避免名稱衝突,所以正常都不會直接使用 Ui_Form 類,而是用命名空間裡的 Ui::Form 類。

需要注意的是 ui_hello.h 標頭檔案裡沒有 Q_OBJECT 宏,它裡面定義的類也沒有從任何視窗或控制元件類繼承。無論是 Ui_Form 類還是 Ui::Form 類,它們都不是視窗類!

準確地說,它們通過 setupUi 函數,輔助該函數引數裡的視窗物件(QWidget *Form)構建圖形介面,它們幫助別的視窗類物件構建圖形介面,僅此而已。當然,在 setupUi 函數里新建的控制元件指標,如 label,是 Ui_Form 或Ui::Form 類裡的成員變數,程式碼裡需要通過這個類的成員變數來操控相應的控制元件。

如果要在專案裡面使用 ui 檔案(其實是 ui_*.h),通常有三種方式:直接使用方式、多重繼承使用方式和成員變數使用方式。本節講述前兩種使用方式,而以後 Qt Creator 自動生成的程式碼就是成員變數使用方式,本節就不重複了。

直接使用 .ui 檔案

直接使用 .ui 檔案的原理非常簡單,建立一個 QWidget 類物件和 Ui::Form 類物件,呼叫 Ui::Form 物件的 setupUi 函數設定一下主表單,然後顯示就行了。我們在 D:QtDemo 資料夾裡新建一個 main.cpp,然後編輯程式碼如下:
#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include "ui_hello.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget *w = new QWidget();  //主視窗
    Ui::Form createUi;  //createUi並不是一個真正的視窗
    createUi.setupUi(w);  //createUi是建立GUI的工具
    w->show();  //w是真正的視窗

    return a.exec();
}
main.cpp 包含了三個標頭檔案 QApplication、QWidget 和 前面用 uic 生成的 ui_hello.h,由於 ui_hello.h 不包含 Q_OBJECT 宏,是不需要用元物件編譯器 moc 處理的。

main 函數裡第一行是圖形介面程式入口物件,第二行建立了一個 QWidget 類物件 w(w 其實是一個指向物件的指標)作為程式的主視窗,w 自己並沒有建立控制元件或設定視窗屬性。

第三行語句:

Ui::Form createUi; 

建立了 Ui::Form 類的物件 createUi ,這個物件自己不是一個視窗,它可以為別的視窗物件設定圖形介面。

第四行語句:

createUi.setupUi(w); 

呼叫了 createUi 物件的 setupUi 函數,該函數接收一個表單物件指標,這裡是 w。setupUi 函數裡面的程式碼會為 w 建立內部的控制元件,設定表單大小等等。

剩下的兩行程式碼是顯示主介面,並進入事件處理迴圈,直到退出。

程式碼解釋完了,接下來我們就開始編譯把。

開啟 Qt 命令列工具,進入 D:QtDemo 資料夾:

cd /d D:QtDemo

執行 g++ 命令:

g++  main.cpp  -std=c++0x  -I"D:Qt5.9mingw53_32include"  -L"D:Qt5.9mingw53_32lib"  -lQt5Core -lQt5Gui -lQt5Widgets  -o main

編譯連結成功後,在輸入main.exe命令就可以看到執行效果。以下是完整流程的截圖:
直接使用.ui文件