一: 新建QT项目
二:QT文件构成
2.1 first.pro
项目管理文件,下面来看代码解析
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
TARGET = main
# 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 \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.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 += core gui
:引入 Qt 核心库和图形界面库(Qt GUI 模块)。如果需要加入新的库,直接在后面添加即可
greaterThan(QT_MAJOR_VERSION, 4)
:条件判断,如果 Qt 版本大于 4(即 Qt 5+),则额外引入 widgets
模块(Qt 5 中独立出来的 GUI 组件)。
CONFIG += c++11
:启用 C++11 标准支持。
TARGET
:指定生成的可执行文件或库的名称(此处为 main
)。如果要修改生成的可执行文件名字,就可以直接修改其后面的名字即可。
QT_DEPRECATED_WARNINGS
:开启对已弃用 Qt API 的编译警告(建议保留,便于代码迁移)。QT_DISABLE_DEPRECATED_BEFORE=0x060000
:禁用 Qt 6.0.0 之前的所有弃用 API(取消注释后,使用这些 API 将导致编译错误)。
SOURCES
:列出项目的源文件(.cpp)。HEADERS
:列出项目的头文件(.h)。
FORMS
:列出 Qt Designer 设计的 UI 文件(.ui),由 uic
工具自动转换为 C++ 代码。
2.2 Headers
该文件里面存放的就是一些头文件,下面看代码解析
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
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;
};
#endif // MAINWINDOW_H
QMainWindow
:继承自 Qt 的主窗口基类,提供标准的应用程序框架(菜单栏、工具栏、状态栏等)。
QT_BEGIN_NAMESPACE
:Qt 使用命名空间组织代码,此处声明 Ui
命名空间,其中的 MainWindow
类由 Qt Designer 自动生成(对应 .ui
文件)。
Q_OBJECT
:Qt 元对象系统的宏,必须包含在所有使用信号与槽的类中。
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
构造函数:接收一个父窗口指针(默认 nullptr
,表示顶级窗口)。
析构函数:负责释放资源,通常由 Qt 自动管理(如删除 ui
对象)。
private:
Ui::MainWindow *ui;
ui
指针:指向 Qt Designer 生成的 UI 类实例,用于访问界面元素(如按钮、标签等)。
关联方式:.ui
文件通过 uic
工具编译为 ui_mainwindow.h
,其中定义了 Ui::MainWindow
类。
2.3 Sources
这里存放的就是项目里的源码C++文件。
2.3.1 main.cpp
入口文件 main.cpp
下面看源码解释
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
QApplication a(argc, argv);
:创建一个 QApplication
对象 a
,它是整个 Qt 应用程序的基础,负责处理命令行参数 argc
和 argv
,初始化应用程序的资源管理等。
MainWindow w;
:创建一个 MainWindow
类的实例 w
,即应用程序的主窗口。
w.show();
:调用主窗口对象 w
的 show
方法,将主窗口显示出来。
return a.exec();
:启动 Qt 应用程序的事件循环,exec
函数会阻塞并等待事件(如鼠标点击、键盘输入等)发生,处理相应事件并重新调度,直到应用程序退出,然后返回退出码。
2.3.2 mainwindow.cpp
主窗口类的实现文件 mainwindow.cpp
下面看源码解释
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
- 构造函数
MainWindow::MainWindow(QWidget *parent)
:MainWindow
类的构造函数,接收一个QWidget
指针作为父窗口(默认为nullptr
,表示顶级窗口)。: QMainWindow(parent)
:使用初始化列表调用基类QMainWindow
的构造函数,传递父窗口指针。: ui(new Ui::MainWindow)
:在初始化列表中创建Ui::MainWindow
类的实例ui
,用于管理界面。ui->setupUi(this);
:在构造函数体中调用ui
的setupUi
方法,该方法会根据.ui
文件中的设计,初始化主窗口的界面元素,将它们添加到主窗口中并进行布局设置等操作。
- 析构函数
MainWindow::~MainWindow()
:MainWindow
类的析构函数,当主窗口对象被销毁时自动调用。delete ui;
:在析构函数中释放ui
指针指向的对象,即释放由 Qt Designer 生成的界面相关资源。
2.4 Forms
存放项目内所有界面文件*.ui
三:信号与槽
3.1信号
当一个对象状态发生变化时发出的通知。它是一种特殊的函数声明,不需要再类中编写函数,只需要声明即可。当特定事件发生时(比如按钮被点击),信号会被发射(emit)
3.2定义信号
只需要在mianwindow.h里声明信号即可。
3.1.1 声明格式
class MyClass : public QObject
{
Q_OBJECT // 必须包含的宏
signals:
void mySignal(); // 无参数信号
void mySignal(int value); // 带参数的信号
void mySignal(const QString& text, bool ok); // 多参数信号
};
- 必须继承
QObject
:信号只能在QObject
的子类中声明。 - 必须包含
Q_OBJECT
宏:该宏启用 Qt 的元对象系统(信号与槽、反射等)。 - 信号只需声明,无需实现:Qt 会自动生成信号的实现代码。
- 返回值必须为
void
:信号不能有返回值。 - 访问控制:
signals
块默认是protected
,但通常无需在意,因为信号只能通过emit
调用,不能直接从外部调用。
3.1.2 信号的参数
信号可以携带任意数量和类型的参数,但需满足:
1.参数类型必须是 Qt 元对象系统支持的类型(基本类型、QString
、QList
等)。
2.自定义类型需使用 Q_DECLARE_METATYPE
注册(如果用于跨线程信号)。
实例代码如下
// 自定义类型
struct MyData {
int value;
QString text;
};
Q_DECLARE_METATYPE(MyData) // 注册元类型
class MyClass : public QObject
{
Q_OBJECT
signals:
void dataChanged(const MyData& data); // 带自定义参数的信号
};
3.1.3 信号的重载
信号可以重载(同名但参数不同):
signals:
void valueChanged(); // 无参数版本
void valueChanged(int newValue); // 带参数版本
3.1.4 信号的继承和重写
信号可以被继承,子类可以:
- 直接使用父类的信号。
- 添加新信号。
- 重写父类信号:信号重写可能导致复杂的调用关系,应谨慎使用。
实例代码如下:
class Parent : public QObject
{
Q_OBJECT
signals:
void parentSignal();
};
class Child : public Parent
{
Q_OBJECT
signals:
void childSignal(); // 新增信号
};
3.1.5 发射信号
使用 emit
关键字发射信号
void MyClass::setValue(int value)
{
if (m_value != value) {
m_value = value;
emit valueChanged(m_value); // 发射信号
}
}
3.3 槽
槽是 Qt 对象接收信号的成员函数,本质上是普通的 C++ 成员函数,但可通过信号触发。
3.3.1 特点
1.可重载:同名但参数不同的槽函数可共存。
2.可继承:子类可继承或重写父类的槽。
3.访问控制:槽可以是public
、protected
或private
。
4.返回值:通常为void
,但也可以有返回值(不过信号无法接收返回值)。
以下两点需要注意:
1. 槽可以是任何成员函数、普通全局函数、静态函数
2. 槽函数和信号的参数和返回值要一致
3.3.2 槽的声明与实现
使用slots
关键字,声明代码如下
class MyClass : public QObject
{
Q_OBJECT
public slots:
void onButtonClicked(); // 无参数槽
void onValueChanged(int value); // 带参数槽
protected slots:
void updateUI();
private slots:
void cleanup();
};
实现代码如下
// 在cpp文件中实现槽函数
void MyClass::onButtonClicked()
{
qDebug() << "Button clicked!";
updateUI();
}
void MyClass::onValueChanged(int value)
{
m_value = value;
emit valueUpdated(m_value); // 槽中也可发射信号
}
3.1.3 信号与槽的连接方式
基本连接格式
connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
sender 是发射信号的对象的名称, signal() 是信号名称。receiver 是接收信号的对象名称, slot() 是槽函数的名称,需要带括号,有参数时还需要指明参数。
1.一个信号可以连接多个槽
2.多个信号可以连接同一个槽
3.当信号和槽函数带有参数时,在 connect()函数里,要写明参数的类型,但可以不写参数名称
3.1.4 槽的参数匹配类型
- 参数数量:槽的参数数量 ≤ 信号的参数数量。
- 参数类型:槽的参数类型必须与信号的对应参数类型 兼容(可隐式转换)。
// 信号声明
void valueChanged(int value, QString text);
// 合法的槽参数:
void slot1(int); // 忽略第二个参数
void slot2(int, QString); // 完全匹配
void slot3(double, QString); // int可转换为double
// 非法的槽参数:
void slot4(QString); // 参数类型不匹配
void slot5(int, QString, bool); // 参数数量过多