目录
三、widget.h 、widget.cpp 与 ui_widget.h之间的关联
Qt的UI文件如何与窗口类关联?
一、widget项目的基本组成
当我们用Qt creater新建一个widget项目时,会有五个文件如图:
- UI.pro
- widget.h
- main.cpp
- widget.cpp
- widget.ui
UI.pro文件和main.cpp文件与本文主要内容关系不大,所以不会涉及这两个文件相关的内容,这两个文件的内容之后在进行阐述。
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 = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
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;
}
widget.ui点开则是设计师界面:
那么这三个文件是怎么关联起来的呢?
当你初次构建该项目的时候,会生成一个 文件,内容如下:
该文件中包含一个 ui_widget.h 的文件,查看 Qt creator编译输出栏可以看到如下信息:
D:\Qt\Qt5.12.4\5.12.4\mingw73_64\bin\uic.exe ..\UI\widget.ui -o ui_widget.h
可以看到 Qt 通过 uic.exe 工具将 widget.ui文件生成了目标文件 ui_widget.h,也就是说 设计师界面的所有内容最终被包含在ui_widget.h这个文件中;
二、ui_widget.h中的内容。
接下来打开 ui_widget.h 文件看看其中的内容:
/********************************************************************************
** Form generated from reading UI file 'widget.ui'
**
** Created by: Qt User Interface Compiler version 5.12.4
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_WIDGET_H
#define UI_WIDGET_H
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Widget
{
public:
void setupUi(QWidget *Widget)
{
if (Widget->objectName().isEmpty())
Widget->setObjectName(QString::fromUtf8("Widget"));
Widget->resize(400, 300);
retranslateUi(Widget);
QMetaObject::connectSlotsByName(Widget);
} // setupUi
void retranslateUi(QWidget *Widget)
{
Widget->setWindowTitle(QApplication::translate("Widget", "Widget", nullptr));
} // retranslateUi
};
namespace Ui {
class Widget: public Ui_Widget {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_WIDGET_H
ui_widget.h中有注释、Ui_Widget类的定义、Ui名称空间的定义。
1.其中最上面三行注释翻译如下:
- 通过读取UI文件'widget.ui'生成;
- 创建者:Qt User Interface Compiler版本5.12.4;
- 警告! 重新编译UI文件时,此文件中所做的所有更改都将丢失!
通过以上注释可以得知:只要我们修改了 widget.ui 文件,然后重新编译,该文件就会重新生成。
2.该文件中定义了一个类 Ui_Widget类,类方法中的对象对应的是 设计师界面的控件!
其中:QMetaObject::connectSlotsByName(Widget);
递归搜索给定对象的所有子对象,并将匹配信号从它们连接到以下格式的对象槽函数:
void on_ <对象名称> _ <信号名称>(<信号参数>);
假设我们的对象有一个QPushButton类型的子对象,其对象名称为button1。 捕获按钮的clicked()信号的槽函数为:
void on_button1_clicked();
3.声明了 名为 Ui 的名称空间,该名称空间中定义了 一个类 Widget,并继承了 Ui_Widget这个类!
三、widget.h 、widget.cpp 与 ui_widget.h之间的关联
现在回看 widget.h 文件中代码:
namespace Ui {
class Widget;
}
在命名空间中进行了 类的前置声明,而该类则是在ui_widget.h中进行定义;
private:
Ui::Widget *ui;
定义了一个Ui::Widget类的指针。
该Ui::Widget类就是 ui_widget.h中定义的,因为ui_widget.h中 的内容 是设计师界面内容的映射, 所以 指针 ui 在实例化之后可以控制、操作界面。
widget.cpp中:
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
包含了ui_widget.h 文件,并 new 了一个 Ui::Widget的实例,赋给Ui。使用 ui->setupUi(this),这个函数的作用是对界面进行初始化,它按照我们在Qt设计器里设计的样子把窗体画出来,把我们在Qt设计器里面定义的信号和槽建立起来。
总结
编译过程中窗口界面 widget.ui 生成 ui_widget.h文件,在该文件的setupUi函数中,将所有的子控件全部画出来,然后将子控件的信号与槽进行连接,实现了界面文件的绘制。
整个实现过程中,又使用了一种设计机制:pImpl ,实现了ui文件更新,只需编译相应的ui_widget.h文件,而不需要重新编译其他任何文件。