Qt信号和槽【2】
文章目录
- 1. 带参数的信号槽
- 2. 信号和槽存在的意义
- 3. 信号和槽断开连接
- 4. lambda表达式定义槽函数
1. 带参数的信号槽
Qt的信号和槽也支持带参数。
当信号带有参数的时候,槽的参数必须和信号的参数一致,此时发射信号的时候,就可以给信号函数传递参数,与之对应的参数,就会被传递到对应的槽函数当中。
参数必须一致,这里的一致主要是类型一致;
个数不一致也可以,不一致的时候,要求信号的参数个数多余槽函数的参数个数,这是因为一个槽可能会绑定多个信号,如果严格要求就意味着绑定到槽的要求变高了,所以适当放宽规则,更多的信号就能绑定到槽函数上。
带参数就可以起到复用代码的效果
在写类的声明的时候,加上了一个
Q_OBJECT
这个宏
在Qt中,如果要某个类,能够使用信号和槽,就必须在类最开始的地方,写下这个宏,这是Qt的硬性规定
这个宏能展开成很多额外的代码
2. 信号和槽存在的意义
所谓的信号槽,最终还是要解决问题,即响应用户的操作
Qt属于GUI开发框架当中,稍微复杂一定的了,其他的可能更简洁一点。
Qt信号槽,较为理想主义:
- 信号和槽解耦,把触发用户操作的控件和处理对应用户的操作逻辑解耦
- 可以实现“多对多”,一个信号可以
connect
到多个槽函数,一个槽函数也可以被多个信号connect
最本质的初心就是让信号和槽之间按照“多对多”的方式进行关联。
不过在实际开发过程当中,很少用到,所以现在新出的一些图形化开发框架,就没有再支持这种多对多了
3. 信号和槽断开连接
可以使用disconnect
来断开信号槽的连接,使用方式和connect
类似
disconncet
用的比较少,大部分情况下,把信号和槽连接上,就不必管了主动断开往往是把信号重新绑定到另一个槽函数上
#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::handleClick1);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handleClick1()
{
this->setWindowTitle("修改窗口标题1");
qDebug() << "handleClick1" ;
}
void Widget::handleClick2()
{
this->setWindowTitle("修改窗口标题2");
qDebug() << "handleClick2" ;
}
void Widget::on_pushButton_2_clicked()
{
//断开 pushbutton 原来的信号槽
disconnect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick1);
//重新绑定
connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick2);
}
如果没有
disconncet
,那么一个信号就会绑定多个槽函数
4. lambda表达式定义槽函数
不了解lambda表达式的,可以先看此篇文章:C++11——lambda表达式
定义槽函数的时候,可以使用lambda
表达式
#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,300);
connect(button, &QPushButton::clicked, this, [](){
qDebug() << "lambda 执行";
});
}
Widget::~Widget()
{
delete ui;
}
这就是lambda
表达式的基本使用方法,但是如果想执行某种操作,例如移动按钮:
这里报错找不到定义,这其实是因为lambda
表达式是一个回调函数,无法直接获取到上层作用域的变量
lambda
为了解决上述问题,可以通过列表捕获,获取到外层作用域中的变量
#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,300);
connect(button, &QPushButton::clicked, this, [button,this](){
qDebug() << "lambda 执行";
button->move(300,300);
this->move(1000,800);
});
}
Widget::~Widget()
{
delete ui;
}
如果想要使用很多外层变量,可以直接写成
[=]
,这样就能捕捉所有上层作用域变量这里要注意的是,要确保捕获的lambda内部变量是有意义的,因为lambda本质是回调函数,用户什么时候点击,并不确定。所有要确保无论用户什么时候点击,捕获的变量都能正确使用,例如这个
button
是在堆上创建的,生命周期随整个窗口,可以随时使用QPushButton *button = new QPushButton(this);
如果开发的时候,槽函数比较简单,而且是一次性,就可以写成这种lambda表达式。
lambda表达式是C++11引入的,对于Qt5及更高的版本,默认就是按照C++11来编译的
如果是Qt4或者更老的版本,就需要手动在
pro
文件加上C++11的编译选项