一、自定义信号与槽
1.1、实现自定义信号与槽
Qt支持自定义信号,下面声明两个类Student与Teacher类,Teacher类定义hungry信号,Student类提供槽函数,两个类的声明与定义如下:
Teacher类声明
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
signals:
// 自定义信号函数
void hungry();
void hungry(QString foodName);
};
#endif // TEACHER_H
Student类声明
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
signals:
public slots:
// 声明两个同名槽函数
void treat();
void treat(QString foodName);
};
#endif // STUDENT_H
Student类定义
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent) : QObject(parent)
{
}
void Student::treat()
{
qDebug() << "treat";
}
void Student::treat(QString foodName)
{
qDebug() << "treat: " << foodName;
}
信号绑定槽函数及触发信息号
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 登录按键绑定槽函数
connect(ui->btn_ok, &QPushButton::clicked, this, &MainWindow::login);
m_pStudent = new Student(this);
m_pTeacher = new Teacher(this);
// 1、不带参数的信号与不带参数的槽函数绑定
// void (Teacher::*pfnTeacherSignal)() = &Teacher::hungry;
// void (Student::*pfnStudentSlot)() = &Student::treat;
// connect(m_pTeacher, pfnTeacherSignal, m_pStudent, pfnStudentSlot);
// 2、带参数的信号与带参数的槽函数绑定
void (Teacher::*pfnTeacherSignal)(QString) = &Teacher::hungry;
void (Student::*pfnStudentSlot)(QString) = &Student::treat;
connect(m_pTeacher, pfnTeacherSignal, m_pStudent, pfnStudentSlot);
}
void MainWindow::login()
{
// // 触发信号(不带参数的信号)
// emit m_pTeacher->hungry();
// 触发信号(带参数的信号)
emit m_pTeacher->hungry("汉堡");
}
1.2、自定义信号特点
自定义信号时,需要注意下面几点
- 要使用关键字signals
- 只需要声明不需要实现
- 信号函数返回值是void
- 信号函数可以重载
1.3、触发自定义信号
触发自定义信号需要调用emit函数,如下:
void MainWindow::login()
{
// // 触发信号(不带参数的信号)
// emit m_pTeacher->hungry();
// 触发信号(带参数的信号)
emit m_pTeacher->hungry("汉堡");
}
二,重载槽函数
槽函数可以重载,Student类定义了两个重载的槽函数,如下:
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
signals:
public slots:
// 声明两个同名槽函数
void treat();
void treat(QString foodName);
};
如何决定具体绑定哪个槽函数?
通过函数指针决定具体绑定哪个槽函数,如下:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 登录按键绑定槽函数
connect(ui->btn_ok, &QPushButton::clicked, this, &MainWindow::login);
m_pStudent = new Student(this);
m_pTeacher = new Teacher(this);
// 1、不带参数的信号与不带参数的槽函数绑定
// void (Teacher::*pfnTeacherSignal)() = &Teacher::hungry;
// void (Student::*pfnStudentSlot)() = &Student::treat;
// connect(m_pTeacher, pfnTeacherSignal, m_pStudent, pfnStudentSlot);
// 2、带参数的信号与带参数的槽函数绑定
void (Teacher::*pfnTeacherSignal)(QString) = &Teacher::hungry;
void (Student::*pfnStudentSlot)(QString) = &Student::treat;
connect(m_pTeacher, pfnTeacherSignal, m_pStudent, pfnStudentSlot);
}
函数重载时可以通过下面三种方法进行绑定
方法一:QOverload
connect(sender, QOverload<bool>::of(&Sender::signal),receiver,
QOverload<bool>::of(&Receiver::slot));
方法二:函数指针
void (Sender:: * ptr)(int) = &Sender::signal;
void (Receiver:: *rptr)(int) = &Receiver::slot;
connect(sender,ptr,receiver,rptr);
方法三:static_cast
connect(sender, static_cast<void(Sender::*)(bool)>(&Sender::signal),
receiver, static_cast<void(Receiver::*)(void)>(&Receiver::slot));
三,信号与槽函数类型要匹配
信号与槽函数参数类型要匹配,例如:信号函数带的参数是QString,那么绑定的槽函数要么不带参数(表示不接收数据),要么是跟信号函数一样的参数,下面的代码编译时会报错,因为信号与槽函数参数类型不匹配,如下:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 登录按键绑定槽函数
connect(ui->btn_ok, &QPushButton::clicked, this, &MainWindow::login);
m_pStudent = new Student(this);
m_pTeacher = new Teacher(this);
// 信号函数不带参数,槽函数带参数(QString),信号与槽函数参数类型不匹配编译时报错
void (Teacher::*pfnTeacherSignal)() = &Teacher::hungry;
void (Student::*pfnStudentSlot)(QString) = &Student::treat;
QMetaObject::Connection conn = connect(m_pTeacher, pfnTeacherSignal, m_pStudent, pfnStudentSlot);
}