QT开发基础知识
Posted 想文艺一点的程序员
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT开发基础知识相关的知识,希望对你有一定的参考价值。
并没有很详细,只有最基本的一些操作
目录
一、QT开发基础
1 .pro 文件的配置
1.1 跨平台配置
之前我们分别在Windows、Mac环境的Qt项目中集成了FFmpeg。
可以发现在.pro文件的配置中,FFmpeg库在Mac、Windows上的位置是有所差异的。这样就会导致.pro文件无法跨平台使用。
# windows
INCLUDEPATH += F:/Dev/ffmpeg-4.3.2/include
# mac
INCLUDEPATH += /usr/local/Cellar/ffmpeg/4.3.2/include
为了实现跨平台配置,可以在配置前面加上平台标识的前缀,表示这个配置只会在对应的平台生效。
# windows
win32:INCLUDEPATH += F:/Dev/ffmpeg-4.3.2/include
win32:LIBS += -LF:/Dev/ffmpeg-4.3.2/lib \\
-lavcodec \\
-lavdevice \\
-lavfilter \\
-lavformat \\
-lavutil \\
-lpostproc \\
-lswscale \\
-lswresample
# mac
macx:INCLUDEPATH += /usr/local/Cellar/ffmpeg/4.3.2/include
macx:LIBS += -L/usr/local/Cellar/ffmpeg/4.3.2/lib \\
-lavcodec \\
-lavdevice \\
-lavfilter \\
-lavformat \\
-lavutil \\
-lpostproc \\
-lswscale \\
-lswresample \\
-lavresample
# linux
# linux:INCLUDEPATH += ...
# linux:LIBS += ...
以后针对每个平台的配置可能会比较多,可以使用大括号来简化。
# windows
win32
INCLUDEPATH += F:/Dev/ffmpeg-4.3.2/include
LIBS += -LF:/Dev/ffmpeg-4.3.2/lib \\
-lavcodec \\
-lavdevice \\
-lavfilter \\
-lavformat \\
-lavutil \\
-lpostproc \\
-lswscale \\
-lswresample
# mac
macx
INCLUDEPATH += /usr/local/Cellar/ffmpeg/4.3.2/include
LIBS += -L/usr/local/Cellar/ffmpeg/4.3.2/lib \\
-lavcodec \\
-lavdevice \\
-lavfilter \\
-lavformat \\
-lavutil \\
-lpostproc \\
-lswscale \\
-lswresample \\
-lavresample
1.2 自定义变量
可以将公共的信息抽取成变量,然后使用 $$ 去访问。我们将 FFMPEG_HOME 设为自定义变量。
# mac
macx
FFMPEG_HOME = /usr/local/Cellar/ffmpeg/4.3.2
INCLUDEPATH += $$FFMPEG_HOME/include
LIBS += -L$$FFMPEG_HOME/lib \\
-lavcodec \\
-lavdevice \\
-lavfilter \\
-lavformat \\
-lavutil \\
-lpostproc \\
-lswscale \\
-lswresample \\
-lavresample
1.3 读取window环境变量
也可以通过 $$() 读取系统的环境变量。比如,我的Windows 中有个叫做 Path 的环境变量。
# 使用message打印环境变量JAVA_HOME的值
message($$(Path))
最后可以在 QT的概要信息 处看到 Path 的打印结果。
2 QT控件的基本使用
为了更好地学习Qt控件的使用,建议创建项目时先不要生成ui文件。(ui文件:在QT界面可以进行控件的拖动)
分析现象:直接运行会生成一个窗口。
分析对应的代码:
- 这个窗口对应的类为 : MainWindow ,继承于 QT 自带的类(QMainWindow)
- 项目分类也很清晰:MainWindow.h :存放 类的声明;MainWindow.cpp:存放 类的定义。
分析 Main 函数
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
QApplication a(argc, argv);
MainWindow w; // 创建一个窗口类:w
w.show(); // 将这个窗口显示出来
return a.exec();
2.1 窗口设置
既然窗口是一个类 MainWindow ,那么我们进行窗口设置的时候,一般在其构造函数当中进行设置。(当其生成的时候,自动调用构造函数,相当于进行初始化操作)
Qt坐标系如下图所示:
- MainWindow 的父控件为 nullptr
2.2 添加一个子控件
(1)添加对应的控件,首先要包含对应的头文件。
(2)new 出来的Qt控件是不需要程序员手动delete的。
(3)Qt内部会自动管理内存:当父控件销毁时,会顺带销毁子控件。
子控件没有父控件的时候:
- 两个窗口会单独显示。
- Pushbutton 必须使用其自己的 show 方法,才能将自己显示出来。
子控件有其父控件的时候:
- this 指针:代表调用这个函数的对象的地址。
- 这时候两个指针会叠在一起,并且 PushButton 不需要单独进行 show。在父控件 show 的时候,子空间也会跟着显示出来。
3 信号与槽
信号:点击控件的时候,会发出一个信号。(相当于是一个中断源)
槽:槽就是处理这个信号的函数。(相当于中断处理函数)
官方参考文档:Signals & Slots | Qt Core 5.15.7
特点:
- 一个信号可以绑定多个槽函数,一个槽也可以处理多个信号。
- QT 里面自带的组件,都有定义好的信号与槽。
怎么查看QT当中自带的信号与槽呢?
- 直接点击这个控件类的 F1,查看QT 官方文档。或者查看其头文件。
- 这个类当中找不到的话,就去查看其对应的父类。(以 QPushButton 为例)
3.1 基本使用
将 按钮的clicked信号 与 主窗口的close槽函数 互相进行绑定。
我们实现我们自己 信号与槽函数:
- 信号的发送者和接收者都必须继承自QObject,Qt中的控件最终都是继承自QObject,比如QMainWindow、QPushButton等。
- 信号与槽,一般以函数的形式呈现。
- 信号:只需要进行声明,不需要进行定义。
- 槽:既需要进行声明,也需要进行定义。
利用 QT IDE 直接生成对应的类文件:
依次填写类的名称、以及继承于哪一个类即可:
- 随后即可生成一个头文件,一个 cpp 文件。
信号的发送者:
sender.h
- single 可以只进行声明,不进行定义
- 应该写在 signals: 下面。
#ifndef SENDER_H
#define SENDER_H
#include <QObject>
class Sender : public QObject
Q_OBJECT // 这个是使用 single 的时候,必须提前声明
public:
explicit Sender(QObject *parent = nullptr);
signals:
void exit(); // single 可以只进行声明,不进行定义
;
#endif // SENDER_H
sender.cpp
#include "sender.h"
Sender::Sender(QObject *parent) : QObject(parent)
信号的接收者:
receiver.h :
-
槽函数必须既进行声明,又进行实现。
-
自定义的槽建议写在 public slots:下面
#ifndef RECEIVER_H
#define RECEIVER_H
#include <QObject>
class Receiver : public QObject
Q_OBJECT
public:
explicit Receiver(QObject *parent = nullptr);
public slots:
void HanderExit();
;
#endif // RECEIVER_H
receiver.cpp :
#include "receiver.h"
#include <QDebug>
Receiver::Receiver(QObject *parent) : QObject(parent)
void Receiver::HanderExit()
qDebug() << "Receiver::HanderExit()";
进行连接:
Mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
;
#endif // MAINWINDOW_H
Mainwindow.cpp
#include "mainwindow.h"
#include <QDebug>
#include <QPushButton>
#include "receiver.h"
#include "sender.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) // 窗口被创建的时候,会自动执行这个函数
// 在堆空间,申请我们自己的控件
Sender *s1 = new Sender;
Receiver *r1 = new Receiver;
// 进行连接
connect(s1,&Sender::exit,r1,&Receiver::HanderExit);
// 发送信号
emit s1 -> exit();
// 自己销毁子控件,只有 QT 自己的控件,才会随着父控件销毁。
delete s1;
delete r1;
MainWindow::~MainWindow() // 窗口销毁的时候
qDebug()<< "MainWindow 被销毁了";
运行结果:槽函数被调用
3.2 参数与返回值
之前我们定义的信号与槽都是 void 类型,其实是可以有的。
- 发信号时的参数会传递给槽
- 信号的参数个数必须大于等于槽的参数个数
- 槽的返回值会返回到发信号的位置
什么是发信号的位置 ?
- a就是接受槽函数的返回值。
int a = emit sender->exit(10, 20);
测试:
// 自定义信号
signals:
int exit(int a, int b);
// 自定义槽
public slots:
int handleExit(int a, int b);
int Receiver::handleExit(int a, int b)
// Receiver::handleExit() 10 20
qDebug() << "Receiver::handleExit()" << a << b;
return a + b; // 槽函数的返回值
// 发出信号
int a = emit sender->exit(10, 20);
// 30
qDebug() << a;
3.3 连接两个信号
不仅是信号与槽可以进行连接,信号与信号之间也可以进行连接。
connect(Object1,Singal 1A, Object2, Singal 2A);
上图,连接了 Object 1 的 Signal 1A 和 Object 2 的 Signal 2A。而 Signal 1A 自己又连接 Slot X 、Signal 2A 自己又连接 Slot Y。
此时的特性:
- 当 Object 1 发出 Signal 1A 时,会触发 Slot X、Slot Y 。
- 当 Object 2 发出 Signal 2A 时,只会触发Slot Y,而不会触发Slot X 。
话句话说:
- 当 Object 1 发出 Signal 1A 信号时,Object 2 会发出 Signal 2A 信号。(所以会触发两个槽函数)
- 当 Object 2 发出 Signal 2A 信号时,Object 2 不会发出 Signal 2A 信号。(所以只会触发一个槽函数)
3.4 Lambda
也可以直接使用 Lambda 处理信号。
发送信号:
- sender, &Sender::exit
槽函数:
connect(sender, &Sender::exit, []()
qDebug() << "lambda handle exit";
);
//直接将 qDebug() << "lambda handle exit"; 作为 槽函数
3.5 ui 文件
如果你的控件是通过ui文件生成的,连接槽函数的步骤会更加简单。
首先建议给按钮们起个有意义的变量名,比如分别叫做:loginButton、registerButton。
对着登录按钮右键,选择转为槽。
选择 clicked信号,然后OK。
此时,Qt Creator已经帮你自动生成了槽函数的声明和实现,当我们点击登录按钮时,就会调用这个函数。
class MainWindow : public QMainWindow
Q_OBJECT
private slots:
// 槽函数的声明
void on_loginButton_clicked();
;
// 槽函数的实现
void MainWindow::on_loginButton_clicked()
qDebug() << "on_loginButton_clicked";
其实,认真观察函数名可以发现一个规律,函数名的命名规则是:on_控件的变量名_事件名。
于是,我们可以尝试编写以下代码。
复制代码C++class MainWindow : public QMainWindow
Q_OBJECT
private slots:
// 槽函数的声明
void on_registerButton_clicked();
;
// 槽函数的实现
void MainWindow::on_registerButton_clicked()
qDebug() << "on_registerButton_clicked";
然后,你点击一下注册按钮,会发现成功调用了MainWindow::on_registerButton_clicked函数。
于是得知:ui文件中的控件会自动跟符合命名规则的槽函数建立连接。
最后,再提示一个知识点:ui文件中的控件可以在代码中通过ui->变量名访问。
C++MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
ui->setupUi(this);
// 通过ui->访问ui文件中的2个按钮
ui->loginButton->setFixedSize(100, 30);
ui->registerButton->setFixedSize(100, 30);
以上是关于QT开发基础知识的主要内容,如果未能解决你的问题,请参考以下文章