在使用 QtCreator 创建 Application 程序时,会自动创建 ***.ui 文件,在文件夹 “build-***-Desktop_Qt_***-Debug” 中生成 ui_***.h,***.ui 可以通过 QtDesigner 进行调整,同时还会在 ***.ui 的文件夹内创建一个同名的 c++ 类。这给我们造成很大的疑惑,到底 Qt 是如何生成 UI?在这里我们做简单分析。
mainwindow.ui 文件:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
自动生成的 ui_mainwindow.h 文件:
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 5.12.8
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
{
public:
QWidget *centralwidget;
QMenuBar *menubar;
QStatusBar *statusbar;
void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
MainWindow->resize(800, 600);
centralwidget = new QWidget(MainWindow);
centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
MainWindow->setCentralWidget(centralwidget);
menubar = new QMenuBar(MainWindow);
menubar->setObjectName(QString::fromUtf8("menubar"));
menubar->setGeometry(QRect(0, 0, 800, 23));
MainWindow->setMenuBar(menubar);
statusbar = new QStatusBar(MainWindow);
statusbar->setObjectName(QString::fromUtf8("statusbar"));
MainWindow->setStatusBar(statusbar);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", nullptr));
} // retranslateUi
};
namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_MAINWINDOW_H
在这里,我们可以看到 ***.h 文件中有 Ui_MainWindow 类,但是这个类没有继承自 Qt 的类,所以显示的窗体不是 Ui_MainWindow,但是其中包含有 UI 中的控件,而且还有一个 void setupUi (QMainWindow *MainWindow) 方法,这个方法传入的的参数是一个 Qt UI 类,这个传入的 UI 类对 Ui_MainWindow 中的控件进行操作。文件最后在 namespace Ui 中定义继承 Ui_MainWindow 的 MainWindow 类。
在自动生成的 c++ 类,h/cpp 文件如下:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QAction>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
// QAction是我自己添加的
QAction* new_action_;
QAction* exit_action_;
};
#endif // MAINWINDOW_H
#include <QAction>
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
new_action_ = new QAction(tr("&New"), this);
new_action_->setShortcut(QKeySequence::New);
exit_action_ = new QAction(tr("E&xit"), this);
exit_action_->setShortcut(QKeySequence::Quit);
menuBar()->addAction(new_action_);
}
MainWindow::~MainWindow()
{
delete ui;
}
我们可以看到 MainWindow 继承 QMainWindow,MainWindow 有个 private 变量 Ui::MainWindow *ui(前文提及的 Ui 空间中继承 Ui_MainWindow 的 MainWindow 类),在构造函数中 ui->setupUi (this)。
结论:
- 程序运行后显示的 UI 实际是 c++ 文件中的 MainWindow。
- MainWindow 中的控件都是通过 ui->setupUi (this),将 Ui_MainWindow 类中的控件(自动或通过 QtDesigner 生成)赋予 MainWindow。
- Ui_MainWindow 和 ui 文件其实只相当于控件库和布局框架,并不真实显示 UI。