Qt入门之UI文件设计与运行机制
QMainWindow 是主窗口类,主窗口具有主菜单栏,工具栏和状态栏,类似于一般的应用程序的窗口
QWidget是所有具体可视界面类的基类,选择QWidget 创建的界面对各种界面组件都可以支持
QDialog是对话框类,可建立一个基于对话框的界面
项目文件组成
1.项目组织文件samp2_1.pro,存储项目设置的文件
#表示加入了 core gui模块。 core gui是Qt用于GUI设计的类库模板,如果创建的是控制台(console)应用程序,就不需要加入 core gui
#Qt类库以模块的形式组织各种功能的类,根据项目涉及的需求,在项目中添加适当的类库模块支持,例如,如果项目中使用到了设计数据库操作的类就需要用到sql的模块,在pro文件中需要增加如下一行
#QT +=sql
QT += core gui
#这是个条件执行语句,表示当QT的版本大于4时,才加入widgets模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
#表示生产的目标可执行文件的名称,即编译后的可执行文件是samp2_1.exe
TARGET = samp2_1
#表示项目使用的模板是app,是一般的应用程序
TEMPLATE = app
CONFIG += c++11
#SOURCES 、HEADERS 、FORMS 记录了项目中包含的源程序文件、头文件和窗体文件(.ui文件)的名称。这些文件列表是Qt Creator自动添加到项目管理文件里面的,用户不需要手动修改。当从项目添加或删除一个文件时,项目管理文件的条目会自动修改
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
2.主函数文件main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv); //Qt的标准应用程序类
Widget w; //定义并创建窗口
w.show(); //显示窗口
return a.exec(); //启动应用程序的执行,开始应用程序的消息循环和事件处理
}
3.窗体相关文件
将项目编译,编译后在项目目录下会自动生成一个ui_widget.h文件(在编译后的文件夹里),这样,对于一个窗体,就有4个文件了 :
widget.h 定义窗体类的头文件,定义了类Widget
widget.cpp Widget类的功能实现源程序文件
widget.ui 窗体界面文件,
ui_widget.h 编译后,根据窗体上的组件及属性、信号与槽的关联等自动生成的一个类的定义文件,类的名称是Ui_Widget
下面分析各个文件的内容及其功能,以及他们是如何联系到一起工作,实现界面的创建与显示的。
3.1 widget.h文件
widget.h文件是窗体类的头文件。在创建项目时,选择窗体基类的QWidget,在widget.h中定义一个继承自QWidget的类的Widget:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget; //声明了一个名称为 Ui 的命名空间,包含一个类Widget。但这个Widget类并不是本文件里定义的类Widget,而是ui_widget.h文件中定义的类,用于描述组件的。这个声明相当与一个外部声明(具体看完ui_widget.h文件才能搞明白)
}
class Widget : public QWidget //本实例窗口类Widget的定义
{
Q_OBJECT //使用Qt的信号与槽机制都必须加入的宏
public:
explicit Widget(QWidget *parent = nullptr); //构造函数
~Widget(); //析构函数
private:
Ui::Widget *ui; //这个指针是用前面namespace Ui里的Widget类定义的,所以指针ui指向可视化设计的界面,要访问界面上的组件,都需要通过这个ui指针
};
#endif // WIDGET_H
3.2 widget.cpp文件
widget.cpp文件是类Widget的实现代码:
#include "widget.h"
#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。可参考:https://blog.csdn.net/GouplovXim1314/article/details/104349423
{
ui->setupUi(this); //这个函数实现了窗口的生产与各种属性的设置、信号与槽的关联
}
Widget::~Widget()
{
delete ui; //析构函数
}
所以,在 ui_widget.h 文件里有一个 namespace 名称为 Ui,里面有一个类 Widget 类用于描述可视化的窗体,且与widget.h里定义的类同名。在Widget类里访问 Ui::Widget类的成员变量或函数需要通过Widget类里的 ui 指针,如果构造函数里执行 ui->setupUi(this)函数那样。
3.3 ui_widget.h文件
ui_widget.h文件是在对 widget.ui 文件编译后生成的一个文件,ui_widget.h会出现在编译后的目录下,或与widget.ui同目录(与项目的 shadow build编译设置有关)。
文件ui_widget.h并不会出现在 Qt Creator 的项目文件目录树里,可手动添加
/********************************************************************************
** Form generated from reading UI file 'widget.ui'
**
** Created by: Qt User Interface Compiler version 5.9.7
**
** 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/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Widget
{
public:
QLabel *label;
QPushButton *btnClose;
void setupUi(QWidget *Widget)
{
if (Widget->objectName().isEmpty())
Widget->setObjectName(QStringLiteral("Widget"));
Widget->resize(400, 300);
QFont font;
font.setFamily(QStringLiteral("Aharoni"));
font.setPointSize(12);
font.setBold(true);
font.setWeight(75);
Widget->setFont(font);
label = new QLabel(Widget);
label->setObjectName(QStringLiteral("label"));
label->setGeometry(QRect(120, 110, 91, 31));
label->setFont(font);
btnClose = new QPushButton(Widget);
btnClose->setObjectName(QStringLiteral("btnClose"));
btnClose->setGeometry(QRect(240, 210, 75, 23));
retranslateUi(Widget);
QObject::connect(btnClose, SIGNAL(clicked()), Widget, SLOT(close()));
QMetaObject::connectSlotsByName(Widget);
} // setupUi
void retranslateUi(QWidget *Widget)
{
Widget->setWindowTitle(QApplication::translate("Widget", "Widget", Q_NULLPTR));
label->setText(QApplication::translate("Widget", "Hello Word", Q_NULLPTR));
btnClose->setText(QApplication::translate("Widget", "\345\205\263\351\227\255", Q_NULLPTR));
} // retranslateUi
};
namespace Ui {
class Widget: public Ui_Widget {};
} // namespace Ui
QT_END_NAMESPACE
#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);
第一行是调用 connect() 函数,将在UI设计器里设置的信号与槽的关联转换为语句。
第二行是设置槽函数的关联方式,用于将UI设计器自动生产的组件信号的槽函数与组件信号关联
所以:在Widget 的构造函数里调用 ui->setupUi(this),就实现了窗体上组件的创建、属性设置、信号与槽的关联
-
定义 namespace Ui,并定义一个从 Ui_Widget 继承的类 Widget