文章目录
什么是信号和槽
什么是信号?什么是槽?
-
信号的发送者发送的是具体的信号,信号的接收者,对信号的处理(槽函数)
-
信号槽的优点:松散耦合,信号发送端和接收端本身是没有关联的,通过concent连接,将两端耦合在一起。
-
连接函数 :connect(参数1,参数2,参数3,参数4)
-
参数
- 参数1 信号的发送者
- 参数2 发送的信号(函数地址)
- 参数3 信号的接受者
- 参数4 处理的槽函数 (函数的地址)
-
松散耦合
实现 点击按钮 关闭窗口的案例
connect(btn , &QPushButton::click , this , &QWidget::close );
//创建一个自己的按钮对象
MyPushButton * myBtn = new MyPushButton;
myBtn->setText("我自己的按钮");
myBtn->move(200,0);
myBtn->setParent(this); //设置到对象树中
//需求 点击我的按钮 关闭窗口
//参数1:信号的发送者 参数2:发送的信号(函数的地址) 参数3:信号的接受者 参数4:处理的槽函数
//connect( myBtn, &MyPushButton::clicked, this, &myWidget::close );
connect( myBtn, &QPushButton::clicked, this, &QWidget::close );
运行结果:当摁完我自己的按钮的图标后,主窗口就会自动关闭,相当于摁了×
自定义信号和槽
无参数的信号和槽
这是一个自定义类的头文件:
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class teacher : public QObject
{
Q_OBJECT
public:
explicit teacher(QObject *parent = nullptr);
signals:
};
#endif // TEACHER_H
- 自定义信号 写到signals:下
- 返回值是void ,信号只需要声明,不需要实现
- 可以有参数,可以重载
1. 信号的声明
这是在teacher类头文件中的信号声明
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = 0);
signals:
//自定义信号 写到signals下
//返回值是void ,只需要声明,不需要实现
//可以有参数,可以重载
//这是一个无参的信号
void hungry();
//一个有参的信号
void hungry(QString foodName);
public slots:
};
#endif // TEACHER_H
由于信号只需要声明不需要实现,所以不需要在主函数中对声明的这个void hungry();
有具体的实现。
对槽函数进行声明
- 早期Qt版本 必须要写到public slots,高级版本可以写到public或者全局下
- 返回值 void ,需要声明,也需要实现
- 可以有参数,可以重载
2. 槽函数的声明
在student的头文件中,对槽函数进行声明
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class student : public QObject
{
Q_OBJECT
public:
explicit student(QObject *parent = nullptr);
// 声明一个槽函数
void treat();
signals:
};
#endif // STUDENT_H
3. 槽函数的实现
在 Student的源文件中对槽函数进行声明和实现。
#include "student.h"
//添加要输出信息的头文件。
#include<QDebug>
student::student(QObject *parent) : QObject(parent)
{
}
void student::treat()
{
qDebug() << "去买饭";
}
4. 信号和槽的连接
- 在wideget头文件中,声明两个指针和一个函数触发信号, 并在源文件中实现他们,然后实现信号和槽函数的连接。
private:
Ui::Widget *ui;
// 自己声明两个默认的指针
teacher * zt;
student * st;
//声明一个函数触发信号,在源文件中实现这个函数。
void classover();
- 在源文件中实现,并建立信号与槽函数的连接。
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建一个老师的对象
this->zt = new teacher(this);
// 创建一个学生的对象。
this->st = new student(this);
//将信号与槽函数进行连接。
connect(zt,&teacher::hungry, st,&student::treat);
//先建立连接,再调用启动信号的函数
classover();
}
void Widget::classover()
{
// 下课函数,调用后触发hungry的信号
//自定义信号输出发时有一个关键字emit
emit zt->hungry();
}
有参数的信号和槽
1. 有参信号的声明
- 带参数的信号声明
信号无需实现也无需声明
signals:
// 无参数的信号,无需实现也无需胜利。
void hungry() ;
// 参数的信号,无需实现也无需声明。
void hungry(QString foodname);
2. 有参槽函数的声明
在头文件中对槽函数的定义
public:
explicit student(QObject *parent = nullptr);
// 声明一个槽函数
void treat();
// 有参数的槽函数
void treat(QString foodname);
3. 有参槽函数的实现
#include "student.h"
//添加要输出信息的头文件。
#include<QDebug>
student::student(QObject *parent) : QObject(parent)
{
}
// 无参槽函数的实现
void student::treat()
{
qDebug() << "去买饭";
}
// 有参槽函数的实现
void student::treat(QString foodname)
{
qDebug() << "去买饭,要吃:" << foodname ;
}
4. 信号与槽的连接
- 在 widget头文件中,定义两个指针和一个实现触发信号的函数,并在原文件中实现他们
private:
Ui::Widget *ui;
// 自己声明两个默认的指针
teacher * zt;
student * st;
//声明一个函数触发信号,在源文件中实现这个函数。
void classover();
- 在源文件中实现指针的声明,信号与槽函数的连接
// 创建一个老师的对象
this->zt = new teacher(this);
// 创建一个学生的对象。
this->st = new student(this);
// 连接带参数的信号和槽
// 指针 -> 地址
// 函数指针 -> 函数地址
void (teacher::*teachersignal)(QString) = &teacher::hungry ;
void (student::*studentsolt)(QString) = &student::treat;
connect(zt,teachersignal, st,studentsolt);
// 触发信号
classover();
// 触发函数
void Widget::classover()
{
// 下课函数,调用后触发hungry的信号
//自定义信号输出发时有一个关键字emit
//emit zt->hungry();
emit zt->hungry("煎饼卷大葱");
}
输出结果:
会发现输出结果中有双引号。如果要去掉双引号的话,需要将QString转成char*
// 有参考函数的实现
void student::treat(QString foodname)
{
// 将QString转成char*:用tuutf8是先转成QByteArray,再转char*
qDebug() << "去买饭,要吃:" << foodname.toUtf8().data();
}
输出结果:
按钮触发信号连接槽
通过一个信号来触发另一个信号,创建一个下课的按钮,通过这个按钮来触发下课信号函数。
// 创建一个老师的对象
this->zt = new teacher(this);
// 创建一个学生的对象。
this->st = new student(this);
// 连接带参数的信号和槽
// 指针 -> 地址
// 函数指针 -> 函数地址
void (teacher::*teachersignal)(QString) = &teacher::hungry ;
void (student::*studentsolt)(QString) = &student::treat;
connect(zt,teachersignal, st,studentsolt);
classover();
//创建一个下课按钮
QPushButton *bth =new QPushButton("下课",this);
//设置窗口大小
this->resize(600,400);
//点击按钮,触发下课。
connect(bth,&QPushButton::clicked,this,&Widget::classover);
点完下课按钮后。
链接过程
信号链接信号
// 创建一个老师的对象
this->zt = new teacher(this);
// 创建一个学生的对象。
this->st = new student(this);
//创建一个下课按钮
QPushButton *bth =new QPushButton("下课",this);
//设置窗口大小
this->resize(600,400);
// 无参信号连接槽
void (teacher::*teachersignal2)(void) = &teacher::hungry ;
void (student::*studentsolt2)(void) = &student::treat;
connect(zt,teachersignal2, st,studentsolt2);
// 信号链接信号
connect(bth,&QPushButton::clicked,zt,teachersignal2);
连接的断开
关键字:disconnect
断开连接的参数和建立连接的参数是相同的,想断开哪个连接,直接传递建立连接的参数。
// 信号链接信号
connect(bth,&QPushButton::clicked,zt,teachersignal2);
// 断开上面的连接
disconnect(bth,&QPushButton::clicked,zt,teachersignal2);
拓展
1. 信号是可以连接信号
2. 一个信号可以连接多个槽函数
3. 多个信号 可以连接 同一个槽函数
4. 信号和槽函数的参数 必须类型一一对应
5. 信号和槽的参数个数 是不是要一致?信号的参数个数 可以多余槽函数的参数个数