文章目录
- 1、信号与槽的参数
- 2、为什么要有信号槽机制?
- 3、断开并重新连接
- 4、槽函数lambda写法
1、信号与槽的参数
信号和槽可以带参数,当信号带有参数时,槽的参数必须和信号的一致,此时发送信号就可以给信号函数传递实参,那么对应的参数就会传到对应的槽函数中,这样就是信号给槽传参了。
// widget.h
public:
Widget(QWidget *parent = nullptr);
~Widget();
signals:
void mySignal(const QString& text);
private slots:
void handleMySignal(const QString& text);
void on_pushButton_clicked();
// widget.cpp
void Widget::handleMySignal(const QString& text)
{
this->setWindowTitle(text);
}
void Widget::on_pushButton_clicked()
{
connect(this, &Widget::mySignal, this, &Widget::handleMySignal);
// 连接好后用emit来发送信号
emit mySignal("带参数的信号");
}
按照代码逻辑来看,传的参数被复用了。可以再拖过去一个按钮,也改它的槽函数。顺便把连接代码放在类中。widget.cpp中:
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(this, &Widget::mySignal, this, &Widget::handleMySignal);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handleMySignal(const QString& text)
{
this->setWindowTitle(text);
}
void Widget::on_pushButton_clicked()
{
emit mySignal("这是信号1");
}
void Widget::on_pushButton_2_clicked()
{
emit mySignal("这是信号2");
}
运行后点击不同按钮标题就有不同变化,也就起到了复用的效果。
假如信号函数比槽函数的参数量更多,依然是可以正常运行的,反之则不行。
一个槽函数会和多个信号绑定,所以如果严格一致,那么就无法绑定很多信号。如果参数量之间不一致,槽函数的参数有多少个,就会按照信号的参数顺序来拿到信号的前几个参数。这样至少确保槽函数的每个参数都是有值的。
信号函数和槽函数的参数类型得匹配,类型要一样。
如果要让某个类能够使用信号和槽,就必须在类最开始写上Q_OBJECT宏。
2、为什么要有信号槽机制?
实际上,这个机制有点复杂,而GUI开发框架对此做得更简洁。网页中响应用户操作也是用回调函数,但是它可以很简单地写出来,比如:
button.onclick = handle;
function handle(){
}
并不需要一个connect来做连接。
Qt这样做的原因主要是信号与槽可以做到多对多,所以就有上面的槽函数可以对应多个信号,并且记录下来各个对应关系。这样的思路和数据库类似,数据库也是有多对多,一对多,一对一的关系。
不过实际开发中,多对多也不是必需的。
3、断开并重新连接
通常断开是为了把信号和别的槽函数连接。断开用disconnec。
拖过去两个按钮,一个按钮我们自定义槽函数,另一个切换按钮修改给定的槽函数。
// widget.h
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;
};
// widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handleClick()
{
this->setWindowTitle("标题被修改");
qDebug() << "handleClick";
}
void Widget::handleClick2()
{
this->setWindowTitle("已切换");
qDebug() << "handleClick2";
}
void Widget::on_pushButton_2_clicked()
{
// 1. 断开连接
disconnect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick);
// 2. 重新绑定
connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick2);
}
如果不写disconnect,那么这个信号就会绑定两个槽函数,点击切换按钮后再去点击第一个按钮,那么handleClick和handleClick2都会打印出来,标题改为已切换,也就是说两个槽函数都会被执行。
4、槽函数lambda写法
lambda本质是一个匿名函数,用来作回调函数很方便。
#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(330, 250);
connect(button, &QPushButton::clicked, this, []() {
qDebug() << "lambda函数被执行";
});
}
如果要在lambda函数里使用button这个对象,就写在捕获里
connect(button, &QPushButton::clicked, this, [button, this]() {
qDebug() << "lambda函数被执行";
button->move(330, 300);
this->move(100, 200);
});
this的move就是把整个框都移动。要捕获所有变量就写成[=]。lambda的写法和C++的一样,=传值,&引用传递。当然得在.pro文件中写上CONFIG += c++11才行。
结束。