QT初识(2)
- 创建好项目之后,多了些什么东西?
- main.cpp
- widget.h
- widget.cpp
- widget.ui
- .pro项目工程文件
我们今天来继续了解QT。如果没看过上一次QT初识的小伙伴可以点击这里:
https://blog.csdn.net/qq_67693066/article/details/137194408
创建好项目之后,多了些什么东西?
创建好的项目会多出这么几个文件:
我们先从main.cpp程序的入口开始看:
main.cpp
main.cpp中的代码还是比较简单的:
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
这段C++代码是使用Qt库开发GUI应用程序的标准入口点代码,它创建并运行一个基于QWidget的简单桌面应用程序。下面是逐行解释:
#include "widget.h"
- 这一行包含了名为
widget.h
的头文件,通常这是用户自定义的窗口类声明的地方。在Qt应用程序中,Widget
通常是指继承自QWidget
类的自定义窗口类,它定义了应用程序主窗口的界面布局和功能。
#include <QApplication>
- 这行代码包含了
QApplication
类的头文件,这是所有Qt GUI应用程序的基础类,负责管理应用程序的事件循环、应用程序的生命周期以及窗口部件间的消息传递。
int main(int argc, char *argv[])
{
- 这是C++程序的主入口函数,接受两个参数:
argc
(命令行参数的计数)和argv
(指向命令行参数数组的指针)。
QApplication a(argc, argv);
- 创建一个
QApplication
对象实例a
,传入argc
和argv
参数,这样Qt应用程序就可以处理命令行参数,并且能够正确初始化事件循环和应用程序环境。
Widget w;
- 创建一个
Widget
类的对象w
,这个对象将是应用程序的主窗口或用户界面。
注意一下,这个Widget类的对象是我们创建项目时勾选的,所以就生成了Widget类这么一个对象。同时要注意Widget的父类是QWidget。
w.show();
- 调用
Widget
对象w
的show()
函数,使窗口可见,也就是在屏幕上显示应用程序窗口。
return a.exec();
- 调用
QApplication
对象a
的exec()
方法,开始执行Qt应用程序的事件循环。在此期间,程序会监听用户的输入、处理窗口消息和其他事件,直到退出事件(如关闭主窗口、接收到退出命令等)发生。exec()
函数返回一个整数值,通常用来表示应用程序的退出状态。
总结起来,这段代码的主要作用是初始化Qt应用程序,创建并显示一个Widget
窗口,并开始处理用户交互和系统事件,直至应用程序结束。
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
最重要的一部分在于如何理解和使用这个Widget
类,它是继承自QWidget
并结合Qt的元对象系统的GUI组件的基础结构:
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
1. 继承自QWidget
Widget
类作为用户界面的主要容器,通过继承自QWidget
获得了显示窗口以及容纳各种Qt GUI控件的能力。QWidget
是所有可显示窗口部件的基础类,它提供了基本的窗口管理、事件处理、布局管理以及绘图环境等功能。
2. Q_OBJECT宏
Q_OBJECT
宏在这个类的声明中是非常关键的,它让Widget
类能够利用Qt的元对象系统。元对象系统提供了诸如信号和槽机制(用于对象之间的异步通信)、属性系统(用于动态改变对象状态)以及国际化支持等功能。没有Q_OBJECT
宏,这些特性将不可用。
3. 构造函数和析构函数
Widget(QWidget *parent = nullptr);
这个构造函数初始化一个Widget
对象,可以指定一个父窗口部件。如果指定了父窗口,则该Widget
将成为父窗口的孩子,这会影响它的行为,比如当父窗口关闭时,子窗口也会自动关闭;另外,在布局管理上,子窗口的大小和位置通常由父窗口决定。
~Widget();
这是析构函数,当Widget
对象生命周期结束时,系统会自动调用它来释放资源。在此处可能需要手动清理或者删除Ui::Widget
对象,但通常情况下,如果Ui::Widget
是在Widget
类的构造函数中正确初始化的(例如通过setupUi()
方法),那么在Widget
析构时,Ui::Widget
也会随之释放。
4. 成员变量Ui::Widget *ui
private: Ui::Widget *ui;
这个私有成员变量指向一个Ui::Widget
类型的对象,它是用户界面的具体实现。在实际的.cpp
文件中,通常会有类似这样的代码:
Widget::Widget(QWidget *parent)
: QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this); // 初始化用户界面
}
这里通过构造函数初始化
ui
,并调用setupUi()
来加载UI文件(由Qt Designer设计并转换成代码的用户界面布局)。这样,ui
对象就包含了所有界面上的控件及其布局信息,程序员可以通过ui
成员变量访问和操作这些控件。
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::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); }
- 关键点: 构造函数初始化了一个继承自
QWidget
的新Widget
对象,同时创建了一个新的Ui::Widget
实例。 - 设计用户界面:
Ui::Widget
是由Qt Designer工具自动生成的,它包含了界面上所有控件的布局和属性信息。 - 设置界面:
ui->setupUi(this)
是核心步骤,它将预设计的界面布局和控件绑定到当前Widget
对象上,实现了图形界面的实际构建。
- 关键点: 构造函数初始化了一个继承自
-
析构函数:
Widget::~Widget() { delete ui; }
- 关键点: 析构函数在
Widget
对象生命周期结束时清理资源。 - 内存管理: 使用
delete ui;
来释放之前在构造函数中动态分配给成员变量ui
的内存空间,遵循C++中“谁创建谁释放”的原则,防止内存泄漏。
- 关键点: 析构函数在
同时注意一下:ui->setupUi(this);
这一行代码与.ui
文件(如widget.ui
)有直接且密切的关系。
在Qt开发环境中,通常会使用Qt Designer工具来设计应用程序的图形用户界面(GUI)。这个工具生成的界面布局被保存在一个
.ui
文件中,该文件包含了窗口、按钮、标签等各种控件以及它们之间的关系、布局等信息。
当我们在C++代码中通过Ui::Widget
类(通常由Qt uic工具从.ui
文件自动生成对应的ui_widget.h
头文件)创建一个对象,并调用其setupUi()
成员函数时,实际上是将.ui
文件中定义的界面布局加载到当前的QWidget
子类实例(在这个例子中是Widget
类的对象)上。
所以,ui->setupUi(this);
的作用就是根据.ui
文件中的设计将用户界面的所有元素和布局配置应用到this
所指的那个Widget
实例中,实现图形界面的设计与实际C++逻辑的连接。
widget.ui
双击这个文件,我们就会进入一个图形化的编辑器,就是我们之前讲的QT Desinger:
如果我们点击一下左侧栏的编辑选项,就会看到这个ui文件本来的原貌:
.pro项目工程文件
我们还要看一下左上方的以.pro结尾的项目工程文件:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
它是Qt Creator IDE用于构建项目时的项目配置文件。.pro
文件用于指定项目所需的模块、编译选项、源文件、头文件、UI文件以及其他构建相关的信息。以下是逐行解释:
QT += core gui
: 指定该项目需要用到Qt的核心库(core)和图形用户界面库(gui)。greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
: 如果Qt版本大于4,则添加widgets
模块。这是因为Qt5开始引入了新的Widgets模块,而在Qt4中,widgets功能包含在gui
模块中。CONFIG += c++11
: 启用C++11标准编译器特性支持。DEFINES += QT_DEPRECATED_WARNINGS
: 定义宏以便在使用Qt已弃用的API时产生编译警告。- 下面注释部分提到,可以进一步定义
QT_DISABLE_DEPRECATED_BEFORE
来阻止使用特定Qt版本之前弃用的API编译通过。SOURCES += main.cpp widget.cpp
: 指定项目中的源代码文件,这里包括主程序入口main.cpp
和自定义Widget类的实现widget.cpp
。HEADERS += widget.h
: 指定项目中的头文件,这里包含自定义Widget类的声明widget.h
。FORMS += widget.ui
: 指定项目中使用Qt Designer设计的UI文件,这里是widget.ui
,它会被uic工具转换成C++代码并整合进项目。
这些其实都是在我们创建项目时,QT自动帮我们创建好的。一般来说,初学者一般都是不用改这些文件的。
还有就是如果我们运行了一次程序,会自动出现一个文件:
这个就是qmake的build(有点像cmake),里面的文件都有这些:
这些都是qmake帮我们构建好的,其实跟cmake的效果差不多。