在Qt中手動添加ui文件


1.怎么添加UI文件

我們知道在新建項目的時候,可以選擇添加*.ui和不添加兩種。

當添加上ui 文件的時候,我們可以利用designer來添加控件,直觀上看到界面的布局,控件的外觀

如果沒有添加ui文件,那么久只能用代碼生成。

那么如果有一個現有的類(不帶ui文件),可否給他新增ui文件呢?

答案是可以。畢竟qt designer form 的簡介就是

Creates a Qt Designer form that you can add to a Qt Widget Project. This is useful if you already have an existing class for the UI business logic.

目錄結構:

 

 

第一步:右鍵項目名稱->添加新文件->Qt->Qt designer Form->Widget->**.ui

第二步:編譯。編譯下會生成ui_**.h

第三步:在要添加界面的類的頭文件內這樣寫:

#ifndef WIDGET1_H
#define WIDGET1_H

#include <QWidget>

namespace Ui {   //新增的
 class Form;
}

class Widget1 : public QWidget
{
    Q_OBJECT

    public:
    Widget1(QWidget *parent = 0);
    ~Widget1();
    private :
    Ui::Form *ff;   //新增的
};

#endif // WIDGET1_H

第四步:在其對應的.cpp文件內:

#include "widget1.h"
#include "QPushButton"
#include "ui_form.h"   //新增的
#include <QLabel>


Widget1::Widget1(QWidget *parent)
    : QWidget(parent),ff(new Ui::Form)  //新增的

{

    QPushButton *a=new QPushButton(this);
    a->setText("a");
    QLabel *vv=new QLabel(this);
    vv->setText("shsh");
    vv->move(100,20);
    ff->setupUi(this);
}

Widget1::~Widget1()
{

}

5.在ui界面的頭文件內這樣寫改

/********************************************************************************
** Form generated from reading UI file 'form.ui'
**
** Created by: Qt User Interface Compiler version 5.11.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/

#ifndef UI_FORM_H
#define UI_FORM_H

#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_Form
{
public:
    QPushButton *pushButton;

    void setupUi(QWidget *Form)
    {
        if (Form->objectName().isEmpty())
            Form->setObjectName(QStringLiteral("Form"));
        Form->resize(400, 300);
        pushButton = new QPushButton(Form);
        pushButton->setObjectName(QStringLiteral("pushButton"));
        pushButton->setGeometry(QRect(240, 180, 75, 23));

        retranslateUi(Form);

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

    void retranslateUi(QWidget *Form)
    {
        Form->setWindowTitle(QApplication::translate("Form", "Form", nullptr));
        pushButton->setText(QApplication::translate("Form", "PushButton", nullptr));
    } // retranslateUi

};

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

QT_END_NAMESPACE

#endif // UI_FORM_H

6.試一試:

在ui界面上直接拖拽控件,看最終的顯示結果:

 

 7.顯示結果:

 

 2.為什么?

單繼承方式是相對於后面要講的多繼承方式,單繼承方式也稱組合(即委托或代理)方式。單繼承方式簡單來說就是在代碼中首先要自定義一個子類(例如下文中的GoToCellDialog類),該類要從form對應的窗體類(或其兼容的子類)派生;並用ui生成的類定義一個類里的成員變量,該成員變量可以是值也可以是指針,根據使用成員變量的形式不同,又分為成員變量和指針成員變量兩種形式。這樣在GoToCellDialog的構造函數中可以直接調用ui和ui中的變量和函數,使用起來很方便。

  • 使用成員變量

      即將 Ui::GotoCellDialog ui; 作為類GotoCellDialog(只繼承自QDialog,單一繼承)的成員變量。這里有一點值得注意的地方,就是ui文件提供的類被包含在了名為Ui的name space里,這樣做的目的是將ui文件的命名空間與用戶的代碼分離,避免兩者出現命名沖突的情況。

 

  • 使用指針成員變量

       與成員變量形式相似,唯一不同的是,將Ui::GoToCellDialog聲明為指針成員,即 Ui::GoToCellDialog *ui;
3.更加詳細的資料補充

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 所示。

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

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

然后對項目進行編譯和運行,可以出現如圖 5 所示的窗口,單擊“Close”按鈕可以關閉程序。

具有 Close 按鈕的“Hello World”程序
圖 5 具有 Close 按鈕的“Hello World”程序

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

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

表 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種使用形式在這篇文章中得到了很好的闡述

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM