【Qt】信号和槽机制
目录
1.信号和槽的理解
Qt内置类的继承关系
2.connect方法
参数
使用示例
2.1 disconnect断开信号槽
2.2 查看内置类型的信号和槽
3.自定义槽函数
3.1 代码方式自定义槽函数
3.2 图形化方式自定义槽函数
4.自定义信号
5.带参数的信号和槽
6.信号和槽的关联关系
7.信号和槽机制的意义
8.lamda表达式作槽函数
1.信号和槽的理解
信号的三个要素
1.信号源 2.信号类型 3.信号处理方法
Qt
信号源:由哪个控件发出信号
信号类型:用户不同的操作,会触发不同的信号(如:点击按钮,触发点击信号;在输入框移动光标,触发移动光标信号;勾选复选框,选择一个下拉框,都会触发不同信号)
信号处理方式:槽(slot)-》函数
槽函数,本质上就是信号处理的回调函数。
connect()
由QObject提供的静态成员函数。
Qt内置类的继承关系
Qt内置类的都有继承关系,所以继承Qbject的所有子类都能调用connect方法。
2.connect方法
1.介绍
connect (const QObject *sender,
const char * signal ,
const QObject * receiver ,
const char * method ,
Qt::ConnectionType type = Qt::AutoConnection )
参数
使用前四个参数
1.信号源
2.信号类型
3.接收者
4.处理方法
参数1和参数2 、参数3和参数4 类型必须匹配:1.类对象指针 2.内置信号指针或父类信号的指针
参数2和参数4,为函数指针。
查看我们传入数据的类型:
函数指针类型void(*)()
,void(*)()
查看函数声明:
我们都知道,不同类型的指针不能相互赋值(除非强转)。
原因,该声明为旧版本声明,传参方法有所不同,需要搭配SIGNAL宏和SLOT宏来传参。
如:connect(button,SIGNAL(&QPushButton::ckicked),this,SLOT(&Widget::close));
宏的作用是,将函数指针类型,转为char*类型。
从Qt5开始对写法进行了简化,不再需要使用宏了,而是为connect提供函数重载。
重载函数的2,4参数为泛型参数,允许传入任意类型。
版本问题:
Qt5的connect支持类型检测,4中connect需要搭配SIGNAL和SLOT宏使用,并不支持类型是否一致的检测。
使用示例
实现点击按钮关闭窗口
close是Qwidget内置的槽函数,所以继承自QWidget的Widget类也能调用该函数。
2.1 disconnect断开信号槽
参数和connect基本一致。
2.2 查看内置类型的信号和槽
那么,close槽和clicked信号,如何得知呢?
看文档,F2
clicked:点击鼠标(按下+释放鼠标)
pressed:按下
released:释放
toggled:状态切换,复选框
3.自定义槽函数
语法:
1.可以作为普通成员函数声明定义
2.public slots: 函数声明
3.1 代码方式自定义槽函数
添加一个成员函数,作为自定义信号处理的槽函数。
alt+回车,添加函数定义
#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* button=new QPushButton(this);
button->setText("按钮");
button->move(100,100);
connect(button,&QPushButton::clicked,this,&Widget::HandelClicked);
}
Widget::~Widget()
{
delete ui;
}
void Widget::HandelClicked()
{
//按下按钮,修改窗口标题
this->setWindowTitle("按钮已经按下");
}
3.2 图形化方式自定义槽函数
1.右键,转到槽,选择信号
自动添加函数声明和定义
2.定义槽函数
原理:如何实现关联信号和槽?
ui文件生成的头文件内部调用,关联函数。
该函数自动将信号和符合命名规则的槽函数关联。
若不符合规则,则报错,无匹配函数。
规则:
函数名on_控件ObjectName属性_信号
4.自定义信号
语法:1.signals: 2.emit触发信号、
注意必须先关联信号和槽,才能emit触发信号,否则若无关联的槽就触发信号,不会调用任何回调来处理信号。
信号函数只需要声明,不需要实现。
示例:
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//关联自定义的信号和槽
connect(this,&Widget::MySignal,this,&Widget::MySlots);
//发射信号
emit MySignal();
}
Widget::~Widget()
{
delete ui;
}
//定义我的槽函数
void Widget::MySlots()
{
qDebug()<<"我的信号和槽";
}
5.带参数的信号和槽
要求:
1.参数类型必须匹配
2.个数要求,信号参数必须等于,或大于,关联的槽函数的参数个数
支持信号和槽的重载。
目的:让同一个信号,可以关联更多的槽函数。
示例:重载带参数的信号和槽
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//初始化函数指针
void (Widget::*signal_p)(QString)=&Widget::MySignal;
void (Widget::*slot_p)(QString)=&Widget::MySlots;
//关联自定义的信号和槽
connect(this,signal_p,this,slot_p);
//发射信号
EmitSignal();
}
Widget::~Widget()
{
delete ui;
}
//定义我的槽函数
void Widget::MySlots()
{
qDebug()<<"我的信号和槽";
}
void Widget::MySlots(QString text)
{
qDebug()<<"带参槽函数被调用:"<<text;
}
void Widget::EmitSignal()
{
emit MySignal("emit传递的信号参数");
}
6.信号和槽的关联关系
- 一个信号,一个槽
- 多个信号,同一个槽
- 一个信号,多个槽
- 一个信号关联一个信号
这种情况下,一个信号触发后,另一个信号会自动发出。
这种方式通常用于将一个信号的发生转发为另一个信号,简化多个信号的触发。
示例:
7.信号和槽机制的意义
1.解耦:信号发送者不需要知道发出的信号被哪个对象的槽函数接收,槽函数也不需要知道哪些信号关联了自己,Qt的信号槽机制保证了信号与槽函数的调⽤。
2.多对多
缺点:与回调函数相⽐,信号和槽稍微慢⼀些。
(定位信号的接收对象所需的开销;遍历所有关联;编组/解组传递的参数;多线程时,信号可能需要排队)
设计初衷是为了信号和槽多对多,但实际设计中,我们还是经常以一对一的方式使用信号槽。
8.lamda表达式作槽函数
Qt5:无需手动添加编译选项。
Qt5以下版本:需采用C++11标准编译文件,在".pro"⽂件中添加: CONFIG += C++11 。
注意捕捉变量的生命周期问题,=拷贝值的方式捕捉。