Qt信号和槽机制
信号和槽机制是Qt引以为豪的机制之一。所谓信号和槽,比如按钮被触发,会发出一个对应的按钮被触发的信号(signal),这种信号类似于水波纹传播没有任何方向性;当某个对象对该信号感兴趣时,就通过连接(connect)函数将此信号和对于发生此信号的处理槽(slot)函数绑定来处理发生的信号
示例
实现点击信号和槽按钮,窗口关闭
创建Qt Widgets Application桌面应用程序,项目名命名为“signal2slot”:
在signal2slot.cpp中输入如下代码:
#include "signal2slot.h"
#include "ui_signal2slot.h"
//包含QPushButton类
#include <QPushButton>
Signal2Slot::Signal2Slot(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Signal2Slot)
{
ui->setupUi(this);
// 重新指定窗口大小
this->resize(400,200);
// 固定窗口显示大小尺寸
this->setFixedSize(400,200);
// 设置窗口标题
this->setWindowTitle("信号和槽");
// 创建一个按钮
QPushButton *btn0 = new QPushButton;
// 设置其父类
btn0->setParent(this);
// 设置按钮文字
btn0->setText("信号和槽");
// 设置按钮位置
btn0->move(160,80);
// 信号和槽连接函数
connect(btn0,&QPushButton::clicked,this,&Signal2Slot::close);
}
Signal2Slot::~Signal2Slot()
{
delete ui;
}
运行结果:点击信号和槽按钮,窗口关闭
主要涉及到两个知识点:
Qt应用程序中以左上角为坐标原点(0,0),向右为X轴正方向,向下为Y轴正方向
connect函数的一般形式为:connect(sender, signal, receiver, slot);
- sender:发出信号的对象
- signal:发送对象发出的信号
- receiver:接收信号的对象
- slot:接收对象在接收到信号之后所需要调用的函数(槽函数)
上面实现的是Qt系统自带的信号和槽,可以在帮助文档中搜到相关信息:
Qt还能自定义信号和槽:
实现过年了,小朋友来我家玩,我要发压岁钱
清空signal2slot.cpp中之前敲入的代码:
#include "signal2slot.h"
#include "ui_signal2slot.h"
Signal2Slot::Signal2Slot(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Signal2Slot)
{
ui->setupUi(this);
}
Signal2Slot::~Signal2Slot()
{
delete ui;
}
创建child和me类:
在child.h中添加拜年信号,信号需要添加到signals下:
#ifndef CHILD_H
#define CHILD_H
#include <QObject>
class Child : public QObject
{
Q_OBJECT
public:
explicit Child(QObject *parent = nullptr);
signals:
void baiNian();
};
#endif // CHILD_H
在me.h中添加发红包槽函数,槽函数需要添加到public slots下:
#ifndef ME_H
#define ME_H
#include <QObject>
class Me : public QObject
{
Q_OBJECT
public:
explicit Me(QObject *parent = nullptr);
signals:
public slots:
void faHongBao();
};
#endif // ME_H
在signal2slot.h中创建我和孩子类以及过年了这个触发条件:
#ifndef ME_H
#define ME_H
#include <QObject>
class Me : public QObject
{
Q_OBJECT
public:
explicit Me(QObject *parent = nullptr);
signals:
public slots:
void faHongBao();
};
#endif // ME_H
在me.cpp中添加发红包这个槽函数的实现代码:
#include "me.h"
#include <QDebug>
Me::Me(QObject *parent) : QObject(parent)
{
}
void Me::faHongBao()
{
qDebug() << "我要发红包";
}
在signal2slot.cpp中初始化对象以及连接信号和槽函数,用emit触发自定义信号:
#include "signal2slot.h"
#include "ui_signal2slot.h"
Signal2Slot::Signal2Slot(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Signal2Slot)
{
ui->setupUi(this);
//创建一个小朋友对象
this->child = new Child(this);
//创建一个我对象
this->me = new Me(this);
//连接
connect(child,&Child::baiNian,me,&Me::faHongBao);
guoNianLe();
}
//过年了的方法
void Signal2Slot::guoNianLe()
{
emit child->baiNian();
}
Signal2Slot::~Signal2Slot()
{
delete ui;
}
运行后会在调试窗口看到输出“我要发红包”字样
当自定义信号和槽出现重载的时候,利用函数指针,来明确指向哪个函数的地址:
child.h中添加重载信号函数:
#ifndef CHILD_H
#define CHILD_H
#include <QObject>
class Child : public QObject
{
Q_OBJECT
public:
explicit Child(QObject *parent = nullptr);
signals:
void baiNian();
void baiNian(QString money);
};
#endif // CHILD_H
me.h中添加重载槽函数:
#ifndef ME_H
#define ME_H
#include <QObject>
class Me : public QObject
{
Q_OBJECT
public:
explicit Me(QObject *parent = nullptr);
signals:
public slots:
void faHongBao();
void faHongBao(QString money);
};
#endif // ME_H
在me.cpp中实现重载槽函数:
#include "me.h"
#include <QDebug>
Me::Me(QObject *parent) : QObject(parent)
{
}
void Me::faHongBao()
{
qDebug() << "我要发红包";
}
void Me::faHongBao(QString money)
{
qDebug() << "我要发" << money.toUtf8().data() << "红包";
}
signal2slot.cpp中实现重载信号和重载槽函数的连接:
#include "signal2slot.h"
#include "ui_signal2slot.h"
Signal2Slot::Signal2Slot(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Signal2Slot)
{
ui->setupUi(this);
//创建一个小朋友对象
this->child = new Child(this);
//创建一个我对象
this->me = new Me(this);
// //连接
// connect(child,&Child::baiNian,me,&Me::faHongBao);
//用函数指针指向函数地址解决重载问题
void(Child:: *baiNianSignal)(QString) = &Child::baiNian;
void(Me:: *faHongBaoSlot)(QString) = &Me::faHongBao;
connect(child,baiNianSignal,me,faHongBaoSlot);
guoNianLe();
}
//过年了的方法
void Signal2Slot::guoNianLe()
{
emit child->baiNian("1000元");
}
Signal2Slot::~Signal2Slot()
{
delete ui;
}
运行后会在调试窗口看到输出“我要发1000元红包”字样
总结:
- 自定义的信号需要声明,不需要实现,可以有参数
- 自定义的槽函数需要声明,需要实现,可以有参数
- 用emit触发自定义信号
- 当自定义信号和槽出现重载的时候,利用函数指针,来明确指向哪个函数的地址
- 信号和槽的参数必须一一对应,参数个数不一定一一对应;信号的参数可以多余槽的参数,但是类型必须一一对应
- 信号可以连接信号
- 一个信号可以触发多个槽函数
- 信号和槽可以断开—disconnect
- 多个信号可以连接同一个槽函数
- 所有new出来的对象不用手动去释放,只要指定好父类;原因是children表中的对象会在窗口关闭后自动释放