1.自定义信号槽
使用connect()可以让我们连接系统提供的信号和槽,同时也可以自定义信号槽。
例如以学生和老师构建类同时当老师触发信号下课同学收到信号执行"吃饭"这一动作代码示例
cpp
#include "SignalAndSlot.h"
//Teacher Student 总框架类用以实现自定义信号槽
SignalAndSlot::SignalAndSlot(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
this->zt = new Teacher(this);
this->st = new Student(this);
connect(this->zt, &Teacher::Hungry, this->st, &Student::treat);
classover();
}
SignalAndSlot::~SignalAndSlot()
{}
void SignalAndSlot::classover()
{
//触发自定义的信号
emit this->zt->Hungry();
}
cpp
#pragma once
#include <QObject> //老师类
class Teacher : public QObject
{
Q_OBJECT
public:
Teacher(QObject* parent = 0);
~Teacher();
signals:
//自定义信号 写到signala下
//1.返回值类型是void
//2.只需要声明,不需要实现
//3.可以有参数,可以发生重哉
void Hungry();
};
cpp
#pragma once
#include <QObject> //学生类
class Student : public QObject
{
Q_OBJECT
public:
Student(QObject* parent = 0);
~Student();
public slots:
//槽函数 写到public slots下,或者public,或者全局函数,或者lambda
//返回值 void
//需要声明 需要实现
//可以有参数 可以重载
void treat();
};
解释:
1.只有继承了QObject类的类,才具有信号槽的能力 。为了使用信号槽,必须继承QObject。凡是QObject类(不管是直接子类还是间接子类),都应该在第一行代码写上Q_OBJECT。不管是不是使用信号槽,都应该添加这个宏。这个宏的展开将为我们的类提供信号槽机制、国际化机制以及 Qt 提供的不基于 C++ RTTI 的反射能力。
2.信号就是一个个的函数名,返回值是 void(因为无法获得信号的返回值,所以也就无需返回任何值),参数是该类需要让外界知道的数据。信号作为函数名,不需要在 cpp 函数中添加任何实现。
3.emit 是 Qt 对 C++ 的扩展,是一个关键字(其实也是一个宏)。emit 的含义是发出,也就是发出Hungry()信号,感兴趣的接收者会关注这个信号。
注意点:
发送者和接收者都需要是QObject的子类(当然,槽函数是全局函数、Lambda 表达式等无需接收者的时候除外);
使用 signals 标记信号函数,信号是一个函数声明,返回 void,不需要实现函数代码;
槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响;
使用 emit 在恰当的位置发送信号;
使用QObject::connect()函数连接信号和槽。
任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数
2.信号和槽重载的问题以及解决
当发生重载的时候要加上函数指针防止程序出现二义性
cpp
//连接有参数的信号和槽 //要用函数指针 指向 函数地址
//这里是以QString类型参数重载的
void(Teacher:: * teacherSignal)(QString) = &Teacher::Hungry;
void(Student:: * studentSlot)(QString) = &Student::treat;
connect(this->zt, teacherSignal, this->st, teacherSignal);
//QString转char*
先调用toUtf-8转为QByteArray
在调用data 转为char*
3. 信号和槽拓展
cpp
void(Teacher:: * teacherSignal1)() = &Teacher::Hungry;
void(Student:: * studentSlot1)() = &Student::treat;
connect(this->zt, teacherSignal1, this->st, studentSlot1);
connect(btn, &QPushButton::clicked, this->zt, teacherSignal1);
//4.信号和槽的参数类型必须一一对应(信号和槽的参数类型必须一样)
//5.信号的参数个数可以多余槽函数,反之不可以,类型相同个数的参数类型也要按顺序一一对应
//6.可以利用disconnect 断开信号槽连接(参数同connect一样)
4.信号连接信号接收信号有参数的连接方式
在Qt中,当你使用信号和槽机制时,信号的发射(emit)会自动将信号所带的参数传递给槽函数或另一个信号。如果你想要在某个信号发射时传递特定的参数给另一个信号或槽,你需要在连接信号和槽时确保它们的参数是匹配的。
对于你给出的代码段,teacherSignal1 是一个指向 Teacher 类中 Hungry 信号的指针,该信号接受一个 QString 类型的参数。同样,studentSlot1 是一个指向 Student 类中 treat 槽的指针,该槽也接受一个 QString 类型的参数。
当你连接 btn 的 clicked 信号到 teacherSignal1 时,你需要确保在发射 teacherSignal1 时传递一个 QString 类型的参数。然而,QPushButton 的 clicked 信号并不传递任何参数,所以你需要使用一种方法来在连接时或信号发射时提供这个参数。
一种常见的做法是使用一个中间槽,该槽在接收到 clicked 信号时被调用,并在其中发射 teacherSignal1,同时传递所需的 QString 参数。例如:
cpp
class MyClass : public QObject {
Q_OBJECT
public:
MyClass() {
connect(btn, &QPushButton::clicked, this, &MyClass::onButtonClicked);
connect(this, &MyClass::teacherSignal1, this->zt, teacherSignal1);
connect(this->zt, teacherSignal1, this->st, studentSlot1);
}
public slots:
void onButtonClicked() {
emit teacherSignal1("I'm hungry!");
}
signals:
void teacherSignal1(QString message);
private:
QPushButton *btn;
Teacher *zt;
Student *st;
};
在这个例子中,MyClass 有一个槽 onButtonClicked,它在 btn 被点击时被调用。在这个槽中,我们发射了 teacherSignal1 信号,并传递了一个 QString 类型的参数 "I'm hungry!"。然后,teacherSignal1 信号被连接到 Teacher 类的 Hungry 信号,最终 Hungry 信号被连接到 Student 类的 treat 槽。这样,当按钮被点击时,消息就会从 btn 传递到 st 的 treat 槽。