Qt項目界面文件(.ui)及其做用(超詳細)

http://c.biancheng.net/view/1820.htmlhtml

 

Qt 項目中,後綴爲「.ui」的文件是可視化設計的窗體的定義文件,如 widget.ui。雙擊項目文件目錄樹中的文件 widget.ui,會打開一個集成在 Qt Creator 中的 Qt Designer 對窗體進行可視化設計,如圖 1 所示。
瀏覽器

集成在 Qt Creator中的 UI 設計器
圖 1 集成在 Qt Creator中的 UI 設計器


本教程後面將稱這個集成在 Qt Creator 中的 Qt Designer 爲「UI 設計器」,以便與獨立運行的 Qt Designer 區別開來。

圖 1 中的 UI 設計器有如下一些功能區域:編輯器

  • 組件面板:窗口左側是界面設計組件面板,分爲多個組,如Layouts、Buttons、Display Widgets等,界面設計的常見組件均可以在組件面板裏找到。
  • 中間主要區域是待設計的窗體。若是要將某個組件放置到窗體上時,從組件面板上拖放一個組件到窗體上便可。例如,先放一個 Label 和一個 Push Button 到窗體上。
  • Signals 和 Slots 編輯器與 Action 編輯器是位於待設計窗體下方的兩個編輯器。Signals 和Slots 編輯器用於可視化地進行信號與槽的關聯,Action 編輯器用於可視化設計 Action。
  • 佈局和界面設計工具欄:窗口上方的一個工具欄,工具欄上的按鈕主要實現佈局和界面設計。
  • 對象瀏覽器(Object Inspector):窗口右上方是 Object Inspector,用樹狀視圖顯示窗體上各組件之間的佈局包含關係,視圖有兩列,顯示每一個組件的對象名稱(ObjectName)和類名稱。
  • 屬性編輯器(Property Editor):窗口右下方是屬性編輯器,是界面設計時最經常使用到的編輯器。屬性編輯器顯示某個選中的組件或窗體的各類屬性及其取值,能夠在屬性編輯器裏修改這些屬性的值。


圖 2 顯示的是選中窗體上放置的標籤組件後屬性編輯器的內容。最上方顯示的文字「LabDemo: QLabel」表示這個組件是一個 QLabel 類的組件,objectName 是LabDemo。函數


界面組件的屬性編輯器
圖 2 界面組件的屬性編輯器


屬性編輯器的內容分爲兩列,分別爲屬性的名稱和屬性的值。屬性又分爲多個組,實際上表示了類的繼承關係,如在圖 2 中,能夠看出 QLabel 的繼承關係是QObject→QWidget→QFrame→QLabel

objectName 表示組件的對象名稱,界面上的每一個組件都須要一個惟一的對象名稱,以便被引用。界面上的組件的命名應該遵循必定的法則,具體使用什麼樣的命名法則根據我的習慣而定,主要目的是便於區分和記憶,也要便於與普通變量相區分。

設置其餘屬性的值只需在屬性編輯器裏操做便可,如設置 LabDemo 的 text 屬性爲「Hello,World」,只需像圖 2 那樣修改 text 屬性的值便可。工具

提示,標準 C++ 語言裏並無 property 關鍵字,property 是 Qt 對標準 C++ 的擴展,使得在 Qt Designer 裏就能夠可視化設置類的數據。佈局

在圖 1 顯示的設計窗體上,放置一個 Label 和一個 Push Button 組件,它們的主要屬性設置見表 3。
字體

表 3 界面組件的屬性設置
ObjectName 類名稱  屬性設置 備註
LabDemo QLabel Text=」Hello, World」
Font.PointSize=20
Font.bold=true
設置標籤顯示文字和字體
btnClose QPushButton Text=」Close」  設置按鈕的文字


編輯完屬性以後,再爲 btnClose 按鈕增長一個功能,就是單擊此按鈕時,關閉窗口,退出程序。使用 Signals 和 Slots 編輯器完成這個功能,如圖 4 所示。ui


信號與槽編輯器中設計信號與槽的關聯
圖 4 信號與槽編輯器中設計信號與槽的關聯


在信號與槽編輯器的工具欄上單擊「Add」按鈕,在出現的條目中,Sender 選擇 btnClose,Signal 選擇 clicked(),Receiver 選擇窗體 Widget,Slot 選擇 close()。這樣設置表示當按鈕 btnClose 被單擊時,就執行 Widget 的 close() 函數,實現關閉窗口的功能。

而後對項目進行編譯和運行,能夠出現如圖 5 所示的窗口,單擊「Close」按鈕能夠關閉程序。this


具備 Close 按鈕的「Hello World」程序
圖 5 具備 Close 按鈕的「Hello World」程序


標籤的文字內容和字體被修改了,窗口標題也顯示爲所設置的標題,而咱們並無編寫一行程序語句,Qt 是怎麼實現這些功能的呢?

爲了搞清楚窗體類的定義,以及界面功能的實現原理,這裏將項目進行編譯。編譯後在項目目錄下會自動生成一個文件 ui_widget.h,這樣對於一個窗體,就有 4 個文件了,各文件的功能說明見表 6。
spa

表 6 窗體相關的 4 個文件
文件名 功能
widget.h 定義窗體類的頭文件,定義了類Widget
widget.cpp Widget 類的功能實現源程序文件
widget.ui 窗體界面文件,由UI設計器自動生成,存儲了窗體上各個組件的屬性設置和佈局
ui_widget.h 編譯後,根據窗體上的組件及其屬性、信號與槽的關聯等自動生成的一個類的定義文件,類的名稱是Ui_Widget


下面分別分析各個文件的內容及其功能,以及它們是如何聯繫在一塊兒工做,實現界面的建立與顯示的。

widget.h 文件

widget.h 文件是窗體類的頭文件。在建立項目時,選擇窗體基類是 QWidget,在 widget.h 中定義了一個繼承自 QWidget 的類 Widget。

下面是 widget.h 文件的內容:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

widget.h 文件有幾個重要的部分。

namespace 聲明

代碼中有以下的一個 namespace 聲明:

namespace Ui {
class Widget;
}

這是聲明瞭一個名稱爲 Ui 的命名空間(namespace),包含一個類 Widget。可是這個類 Widget 並非本文件裏定義的類 Widget,而是 ui_widget.h 文件裏定義的類,用於描述界面組件的。這個聲明至關於一個外部類型聲明(具體要看完 ui_widget.h 文件內的解釋以後才能搞明白)。

Widget 類的定義

widget.h 文件的主體部分是一個繼承於 QWidget 的類 Widget 的定義,也就是本實例的窗體類。

在 Widget 類中使用了宏 Q_OBJECT,這是使用 Qt 的信號與槽(signal 和 slot)機制的類都必須加入的一個宏(信號與槽在後面詳細介紹)。

在 public 部分定義了 Widget 類的構造函數和析構函數。

在 private 部分又定義了一個指針。

Ui::Widget *ui;

這個指針是用前面聲明的 namespace Ui 裏的 Widget 類定義的,因此指針 ui 是指向可視化設計的界面,後面會看到要訪問界面上的組件,都須要經過這個指針 ui。

widget.cpp 文件

widget.cpp 文件是類 Widget 的實現代碼,下面是 widget.cpp 文件的內容。

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

注意到,在這個文件的包含文件部分自動加入了以下一行內容:

#include "ui_widget.h"

這個就是 Qt 編譯生成的與 UI 文件 widget.ui 對應的類定義文件。

目前只有構造函數和析構函數。其中構造函數頭部是:

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)

其意義是:執行父類 QWidget 的構造函數,建立一個 Ui::Widget 類的對象 ui。這個 ui 就是 Widget 的 private 部分定義的指針變量 ui。

構造函數裏只有一行語句:

ui->setupUi(this)

它是執行了 Ui::Widget 類的 setupUi() 函數,這個函數實現窗口的生成與各類屬性的設置、信號與槽的關聯(後面會具體介紹)。

析構函數只是簡單地刪除用 new 建立的指針 ui。

因此,在 ui_widget.h 文件裏有一個 namespace 名稱爲 Ui,裏面有一個類 Widget 是用於描述可視化設計的窗體,且與 widget.h 裏定義的類同名。在 Widget 類裏訪問 Ui::Widget 類的成員變量或函數須要經過 Widget 類裏的 ui 指針,如同構造函數裏執行 ui->setupUi( this) 函數那樣。

widget.ui 文件

widget.ui 是窗體界面定義文件,是一個 XML 文件,定義了窗口上的全部組件的屬性設置、佈局,及其信號與槽函數的關聯等。用UI設計器可視化設計的界面都由 Qt 自動解析,並以 XML 文件的形式保存下來。在設計界面時,只需在 UI 設計器裏進行可視化設計便可,而不用管 widget.ui 文件是怎麼生成的。

下面是 widget.ui 文件的內容:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>336</width>
    <height>216</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>My First Demo</string>
  </property>
  <widget class="QLabel" name="Lablabel">
   <property name="geometry">
    <rect>
     <x>100</x>
     <y>70</y>
     <width>141</width>
     <height>61</height>
    </rect>
   </property>
   <property name="font">
    <font>
     <pointsize>12</pointsize>
     <weight>75</weight>
     <bold>true</bold>
    </font>
   </property>
   <property name="text">
    <string>Hello,World</string>
   </property>
  </widget>
  <widget class="QPushButton" name="btnClose">
   <property name="geometry">
    <rect>
     <x>210</x>
     <y>150</y>
     <width>75</width>
     <height>23</height>
    </rect>
   </property>
   <property name="text">
    <string>Close</string>
   </property>
  </widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections>
  <connection>
   <sender>btnClose</sender>
   <signal>clicked()</signal>
   <receiver>Widget</receiver>
   <slot>close()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>247</x>
     <y>161</y>
    </hint>
    <hint type="destinationlabel">
     <x>167</x>
     <y>107</y>
    </hint>
   </hints>
  </connection>
</connections>
</ui>

ui_widget.h 文件

ui_widget.h 是在對 widget.ui 文件編譯後生成的一個文件,ui_widget.h 會出如今編譯後的目錄下,或與 widget.ui 同目錄(與項目的 shadow build 編譯設置有關)。

文件 ui_widget.h 並不會出如今 Qt Creator 的項目文件目錄樹裏,固然,能夠手工將 ui_widget.h 添加到項目中。方法是在項目文件目錄樹上,右擊項目名稱節點,在調出的快捷菜單中選擇「Add Existing Files…」,找到並添加 ui_widget.h 文件便可。

注意,ui_widget.h 是對 widget.ui 文件編譯後自動生成的,widget.ui 又是經過 UI 設計器可視化設計生成的。因此,對 ui_widget.h 手工進行修改沒有什麼意義,全部涉及界面的修改都應該直接在UI 設計器裏進行。因此,ui_widget.h 也沒有必要添加到項目裏。

下面是 ui_widget.h 文件的內容:

  1. /********************************************************************************
  2. ** Form generated from reading UI file 'widget.ui'
  3. **
  4. ** Created by: Qt User Interface Compiler version 5.9.1
  5. **
  6. ** WARNING! All changes made in this file will be lost when recompiling UI file!
  7. ********************************************************************************/
  8. #ifndef UI_WIDGET_H
  9. #define UI_WIDGET_H
  10. #include <QtCore/QVariant>
  11. #include <QtWidgets/QAction>
  12. #include <QtWidgets/QApplication>
  13. #include <QtWidgets/QButtonGroup>
  14. #include <QtWidgets/QHeaderView>
  15. #include <QtWidgets/QLabel>
  16. #include <QtWidgets/QPushButton>
  17. #include <QtWidgets/QWidget>
  18. QT_BEGIN_NAMESPACE
  19. class Ui_Widget
  20. {
  21. public:
  22. QLabel *label;
  23. QPushButton *btnClose;
  24. void setupUi(QWidget *Widget)
  25. {
  26. if (Widget->objectName().isEmpty())
  27. Widget->setObjectName(QStringLiteral("Widget"));
  28. Widget->resize(336, 216);
  29. label = new QLabel(Widget);
  30. label->setObjectName(QStringLiteral("label"));
  31. label->setGeometry(QRect(100, 70, 141, 61));
  32. QFont font;
  33. font.setPointSize(12);
  34. font.setBold(true);
  35. font.setWeight(75);
  36. label->setFont(font);
  37. btnClose = new QPushButton(Widget);
  38. btnClose->setObjectName(QStringLiteral("btnClose"));
  39. btnClose->setGeometry(QRect(210, 150, 75, 23));
  40. retranslateUi(Widget);
  41. QObject::connect(btnClose, SIGNAL(clicked()), Widget, SLOT(close()));
  42. QMetaObject::connectSlotsByName(Widget);
  43. } // setupUi
  44. void retranslateUi(QWidget *Widget)
  45. {
  46. Widget->setWindowTitle(QApplication::translate("Widget", "My First Demo", Q_NULLPTR));
  47. label->setText(QApplication::translate("Widget", "Hello\357\274\214World", Q_NULLPTR));
  48. btnClose->setText(QApplication::translate("Widget", "Close", Q_NULLPTR));
  49. } // retranslateUi
  50. };
  51. namespace Ui {
  52. class Widget: public Ui_Widget {};
  53. } // namespace Ui
  54. QT_END_NAMESPACE
  55. #endif // UI_WIDGET_H


查看 ui_widget.h 文件的內容,發現它主要作了如下的一些工做:

  1. 定義了一個類 Ui_Widget,用於封裝可視化設計的界面。
  2. 自動生成了界面各個組件的類成員變量定義。在 public 部分爲界面上每一個組件定義了一個指針變量,變量的名稱就是設置的 objectName。好比,在窗體上放置了一個 QLabel 和一個 QPushButton 並命名後,自動生成的定義是:

    QLabel *LabDemo;
    QPushButton *btnClose;

  3. 定義了 setupUi() 函數,這個函數用於建立各個界面組件,並設置其位置、大小、文字內容、字體等屬性,設置信號與槽的關聯。setupUi() 函數體的第一部分是根據可視化設計的界面內容,用 C++ 代碼建立界面上各組件,並設置其屬性。

    接下來,setupUi() 調用了函數 retranslateUi(Widget),用來設置界面各組件的文字內容屬性,如標籤的文字、按鍵的文字、窗體的標題等。將界面上的文字設置的內容獨立出來做爲一個函數 retranslateUi(),在設計多語言界面時會用到這個函數。

    setupUi() 函數的第三部分是設置信號與槽的關聯,本文件中有如下兩行:

    QObject::connect(btnClose, SIGNAL(clicked()), Widget, SLOT(close()));
    QMetaObject::connectSlotsByName(Widget);

    第1 行是調用 connect() 函數,將在 UI 設計器裏設置的信號與槽的關聯轉換爲語句。這裏是將 btnClose 按鍵的 clicked() 信號與窗體 Widget 的 close() 槽函數關聯起來,就是在圖 4 中設置的信號與槽的關聯的程序語句實現。這樣,當單擊 btnClose 按鈕時,就會執行 Widget 的 close() 槽函數,而 close() 槽函數的功能是關閉窗口。

    第 2 行是設置槽函數的關聯方式,用於將 UI 設計器自動生成的組件信號的槽函數與組件信號相關聯。

    因此,在Widget 的構造函數裏調用 ui->setupUI(this),就實現了窗體上組件的建立、屬性設置、信號與槽的關聯。
  4. 定義 namespace Ui,並定義一個從Ui_Widget 繼承的類Widget。

    namespace Ui {
        class Widget: public Ui_Widget {};
    }

提示:ui_widget.h 文件裏實現界面功能的類是 Ui_Widget。再定義一個類 Widget 從 Ui_Widget 繼承而來,並定義在 namespace Ui 裏,這樣 Ui:: Widget 與 widget.h 裏的類 Widget 同名,可是用 namespace 區分開來。因此,界面的 Ui:: Widget 類與文件 widget.h 裏定義的 Widget 類其實是兩個類,可是 Qt 的處理讓用戶感受不到 Ui:: Widget 類的存在,只須要知道在 Widget 類裏用 ui 指針能夠訪問可視化設計的界面組件就能夠了。

相關文件推薦:

Qt .ui文件介紹相關軟件推薦
談.ui文件的用法 這是一篇對Qt項目中ui文件用法的軟件,有對.ui文件的詳細介紹
Qt之UI文件設計和運行機制 這是一篇對Qt項目中各個文件總體介紹的一篇軟文,講的很詳細
Qt中.ui文件的使用 .ui文件有3種使用形式在這篇文章中獲得了很好的闡述
相關文章
相關標籤/搜索