前言
本文将会向你介绍信号与槽中:自定义信号、disconnect、lambda表达式定义槽函数等相关概念
自定义信号
在开发中,很少会使用到自定义信号,在Qt内置的信号,基本上能够覆盖用户的所有操作,足以应付大部分的开发场景
包含Qt5在内以及更高的版本中,槽函数与普通的成员函数已经没有区别,但是信号则是一类特殊函数
1、只需要写出函数声明,并且告诉Qt这是一个”信号“即可,这个函数的定义,是Qt在编译过程中,自动生成的(自动生成的过程,程序员无法进行干预)。因为信号在Qt中是特殊的机制,Qt生成的信号函数的实现,要配合Qt框架做很多既定的操作
2、作为信号函数,这个函数的返回值,必须为void,有没有参数都可以,也可以支持重载
Widget.h文件所需要做的修改如下
一个clicked信号对应了两个槽函数,这样也是符合规定的
private slots:
//点击信号clicked对应的槽函数
void on_pushButton_clicked();
//点击信号clicked对应的槽函数
void on_pushButton_2_clicked();
在Qt中以下情况都是可以的
Widget.cpp文件所需要做的修改如下
对重点代码进行解释说明:
将自定义信号 mySignal 连接到槽函数 handleMySignal,注意connect只是将信号与槽建立了连接,不代表信号发出来了,因此我们还需要进行发送信号。
上一篇文章中我们自定义槽函数,并通过clicked信号触发事件,点击按钮时就调用对应的槽函数(这里不用手动发送信号的原因是:Qt内置的信号(如clicked),不需要手动通过代码来触发,发射信号的代码已经内置到Qt框)
connect(this, &Widget::mySignal, this, &Widget::handleMySignal);
与信号对应的槽函数
void Widget::handleMySignal(const QString& text)
{
this->setWindowTitle(text);
}
点击按钮触发clicked信号所对应的槽函数:功能为发送信号
void Widget::on_pushButton_clicked()
{
emit mySignal("把标题设置为文本一", "");
}
void Widget::on_pushButton_2_clicked()
{
emit mySignal("把标题设置为文本二", "");
}
大致流程如下:
connect将自定义信号 mySignal 连接到槽函数 handleMySignal
点击按钮 =>触发clicked信号 => 执行对应的槽函数:emit mySignal() 槽函数中发送信号 => 执行自定义信号的槽函数handleMySignal()
带参数的信号槽
传参可以起到复用代码的效果,可以通过函数-参数来复用代码
信号函数以及与其对应的槽函数声明:
此时信号触发, 调⽤到槽函数的时候, 信号函数中的实参就能够被传递到槽函数的形参当中
信号函数的参数个数即使超过了槽函数的参数个数,也是被允许的,但是槽的参数个数不能多于信号参数个数,实际开发中最好还是保持参数个数也能匹配⼀致.
因为一个信号,可能会绑定多个槽函数,信号可以向多个槽发出通知,如果严格要求参数个数一致,就意味着信号绑定槽的要求变高了。如果信号的参数个数多于槽的参数个数,Qt将只传递与槽函数参数相对应的信号参数。至少需要确保槽函数的每个参数都是有值的,所以信号给槽传参的个数,可以有多,但是绝不能少为什么允许信号参数的个数可以大于槽函数的参数个数呢?
信号与槽的断开
使⽤ disconnect 即可完成断开.
disconnect 的⽤法和 connect 基本⼀致.
以下我们主要实现通过disconnect达到切换槽函数的作用
widget.h中所需要的修改
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPushButton>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void handleClick();
void handleClick2();
private slots:
void on_pushButton_2_clicked();
private:
Ui::Widget *ui;
QPushButton *pushButton;
};
#endif // WIDGET_H
widget.cpp中所需要的修改
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
pushButton = new QPushButton(this);
pushButton->setText("按钮");
pushButton->move(100, 100); //将按钮的位置设定为 (100, 100),相对于其父窗口的坐标系
connect(pushButton, &QPushButton::clicked, this, &Widget::handleClick);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handleClick()
{
this->setWindowTitle("修改窗口的标题");
qDebug() << "handleClick";
}
void Widget::handleClick2()
{
this->setWindowTitle("修改窗口的标题2");
qDebug() << "handleClick2";
}
void Widget::on_pushButton_2_clicked()
{
disconnect(pushButton, &QPushButton::clicked, this, &Widget::handleClick);
connect(pushButton, &QPushButton::clicked, this, &Widget::handleClick2);
}
切换槽函数d
void Widget::on_pushButton_2_clicked()
{
disconnect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick);
connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick2);
}
(注释1): 槽函数:disconnect:断开名为按钮的控件的clicked信号与其槽函数一的连接。
connect:连接名为按钮的控件与其槽函数二
void Widget::on_pushButton_2_clicked()
{
disconnect(pushButton, &QPushButton::clicked, this, &Widget::handleClick);
connect(pushButton, &QPushButton::clicked, this, &Widget::handleClick2);
}
槽函数一:
void Widget::handleClick()
{
this->setWindowTitle("修改窗口的标题");
qDebug() << "handleClick";
}
槽函数二:
void Widget::handleClick2()
{
this->setWindowTitle("修改窗口的标题2");
qDebug() << "handleClick2";
}
如果点击名为切换槽函数的控件,再点击名为按钮的控件就会调用槽函数二,否则二调用槽函数一
使用lambda表达式定义槽函数
Qt5 在 Qt4 的基础上提⾼了信号与槽的灵活性,允许使⽤任意函数作为槽函数。
但如果想⽅便的编写槽函数,⽐如在编写函数时连函数名都不想定义,则可以通过 Lambda表达式来达到这个⽬的。
Lambda表达式 是 C++11 增加的特性。C++11 中的 Lambda表达式 ⽤于定义并创建匿名的函数对
象,以简化编程⼯作。
Lambda表达式 的语法格式如下:
[ capture ] ( params ) opt -> ret {
Function body;
};
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.cpp所需要做的修改
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* button = new QPushButton(this);
button->setText("按钮");
button->move(200, 200);
connect(button, &QPushButton::clicked, this, [=](){
qDebug() << "lambda 被执行了!";
button->move(300, 300);
});
}
Widget::~Widget()
{
delete ui;
}
由于lambda表达式是一个回调函数,是无法直接获取到上层作用域中的变量的,lambda为了解决这个问题,引入了变量捕获的语法,通过变量捕获,来获取到外层作用域中的变量
如下:无法获取到外部的变量
符号 | 说明 |
---|---|
[a] | 在函数体内部使⽤值传递的⽅式访问a变量 |
[&b] | 在函数体内部使⽤引⽤传递的⽅式访问b变量 |
[=] | 函数外的所有局部变量都通过值传递的⽅式使⽤, 函数体内使⽤的是副本 |
[&] | 以引⽤的⽅式使⽤Lambda表达式外部的所有变量 |
[=, &foo] | foo使⽤引⽤⽅式, 其余是值传递的⽅式 |
[&, foo] | foo使⽤值传递⽅式,其余引⽤传递 |
[this] | 在函数内部可以使⽤类的成员函数和成员变量,= 和 & 形式也都会默认引⼊ |
小结
今天是1024,祝各位平安顺遂哈~