一、概念
(1)信号:特定情况下被发射的事件;
(2)槽:对信号响应的函数;
二、特点
(1)信号(signals):
1.1 自定义信号函数,写在signals下;
1.2 返回值是void,只需要声明,不需要实现;
1.3 参数可有可无,可以重载;
(2)槽(slots):
2.1自定义的槽函数,早期的必须写在public slots下,高版本可以写在public下;
2.2 返回值是void,需要声明也需要实现;
2.3 参数可有可无,可以重载;
2.4 自定义槽函数形式:
2.4.1 类的任意成员函数;
2.4.2 静态函数;
2.4.3 全局函数;
2.4.4 Lambda表达式;
(3)触发自定义的信号函数
3.1 关键字:emit
3.2 通过类对象调用信号函数
eg: void MyWidget::ClassOver()
{
emit te->hungry();
}
3.3 调用位置在信号槽机制之后(先实现信号槽的绑定,再调用信号函数)
(4)Q_OBJECT 关键字
4.1 凡是QObject类(不管是直接子类还是间接子类),都应该在第一行代码写上Q_OBJECT,不能丢失;
4.2 作用:只有继承了QObject类的类,才具有信号槽的能力;
(5)信号和槽的参数类型必须一致,信号函数的参数个数可以多余槽函数;
(6)QT4版本信号槽连接方式
例如:connect(bt, SLGNAL(clicked()), this, SLOT(close()));
6.1优点:参数直观;
6.2缺点:类型不做检测;
三、连接机制
伪代码:connect(信号的发送者,发送的具体信号(函数的地址),信号的接收者,信号的具体处理(函数的地址));
四、优点
松散耦合:信号的发送者和信号的接受者本身没有关联,通过connect函数,将两端耦合在一起;
五、案例
(1)利用系统的信号函数和槽函数 (点击按钮关闭窗口)
//MyWidget.cpp
#include "MyWidget.h"
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
this->bt = new QPushButton("关闭");
//按钮布局
QHBoxLayout *lay = new QHBoxLayout(this);
lay->addStretch();
lay->addWidget(bt);
lay->addStretch();
//信号槽
connect(bt, &QPushButton::clicked, this, &MyWidget::close);
//槽对象也可以用父类(因为子类继承于父类)
connect(bt, &QPushButton::clicked, this, &Widget::close);
}
//MyWidget.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QtWidgets/QWidget>
#include <QPushButton>
#include <QHBoxLayout>
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = Q_NULLPTR);
private:
QPushButton *bt;
};
//mian.cpp
#include "MyWidget.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyWidget w;
w.show();
return a.exec();
}
(2)自定义信号函数和槽函数(下课后,老师触发信号饿了,学生响应请老师吃饭的槽函数)
//Teacher.cpp
#include "Teacher.h"
Teacher::Teacher(QWidget *parent)
: QWidget(parent)
{
}
//Teacher.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QtWidgets/QWidget>
class Teacher : public QWidget
{
Q_OBJECT
public:
Teacher(QWidget *parent = Q_NULLPTR);
private:
signals:
void hungry();
public slots:
};
//Student.cpp
#include "Student.h"
#include <QDebug>
Student::Student(QWidget *parent)
: QWidget(parent)
{
}
void Student::treat()
{
qDebug() << "请老师吃饭!";
}
//Student.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QtWidgets/QWidget>
class Student : public QWidget
{
Q_OBJECT
public:
Student(QWidget *parent = Q_NULLPTR);
private:
signals:
public slots:
void treat();
};
//MyWidget.cpp
#include "MyWidget.h"
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
//创建老师对象
te = new Teacher(this);
//创建学生对象
st = new Student(this);
//信号槽绑定
connect(te,&Teacher::hungry,st,&Student::treat);
//调用下课函数
ClassOver();
}
void MyWidget::ClassOver()
{
//下课后,老师触发饿了的信号
emit te->hungry();
}
//MyWidget.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QtWidgets/QWidget>
#include "Teacher.h"
#include "Student.h"
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = Q_NULLPTR);
private:
void ClassOver();
Teacher *te;
Student *st;
};
//mian.cpp
#include "MyWidget.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyWidget w;
w.show();
return a.exec();
}
(3) 当子定义的信号函数和槽函数出现重载关系
3.1 需要利用函数指针,明确指出函数的地址
void (Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
3.2 QString 转换 char*
foodName.toUtf8().data();
//Teacher.cpp
#include "Teacher.h"
Teacher::Teacher(QWidget *parent)
: QWidget(parent)
{
}
//Teacher.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QtWidgets/QWidget>
class Teacher : public QWidget
{
Q_OBJECT
public:
Teacher(QWidget *parent = Q_NULLPTR);
private:
signals:
void hungry();
void hungry(QString foodName);
public slots:
};
//Student.cpp
#include "Student.h"
#include <QDebug>
Student::Student(QWidget *parent)
: QWidget(parent)
{
}
void Student::treat()
{
qDebug() << "请老师吃饭";
}
void Student::treat(QString foodName)
{
qDebug() << "请老师吃饭,老师要吃" << foodName.toUtf8().data();
//将QString类型转换为char*,作用是取消字符串显示时带双引号。。。
}
//Student.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QtWidgets/QWidget>
class Student : public QWidget
{
Q_OBJECT
public:
Student(QWidget *parent = Q_NULLPTR);
private:
signals:
public slots:
void treat();
void treat(QString foodName);
};
//MyWidget.cpp
#include "MyWidget.h"
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
//创建老师对象
te = new Teacher(this);
//创建学生对象
st = new Student(this);
//定义函数指针
void (Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
void (Student:: *studentSlot)(QString) = &Student::treat;
//信号槽绑定
connect(te,teacherSignal,st,studentSlot);
//调用下课函数
ClassOver();
}
void MyWidget::ClassOver()
{
//下课后,老师触发饿了的信号
/*emit te->hungry();*/
emit te->hungry("鱼香肉丝");
}
//MyWidget.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QtWidgets/QWidget>
#include "ui_MyWidget.h"
#include "Teacher.h"
#include "Student.h"
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = Q_NULLPTR);
private:
Ui::MyWidgetClass ui;
void ClassOver();
Teacher *te;
Student *st;
};
//main.cpp
#include "MyWidget.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyWidget w;
w.show();
return a.exec();
}
(4) 信号1连接信号2,信号2连接槽函数(点击按钮触发限信号,信号去响应槽函数)
4.1 有参数的情况下
//MyWidget.cpp
#include "MyWidget.h"
#include <QHBoxLayout>
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
bt = new QPushButton("下课",this);
QHBoxLayout *ly = new QHBoxLayout(this);
ly->addStretch();
ly->addWidget(bt);
ly->addStretch();
//创建老师对象
te = new Teacher(this);
//创建学生对象
st = new Student(this);
//定义函数指针
void (Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
void (Student:: *studentSlot)(QString) = &Student::treat;
//信号槽绑定
connect(bt, &QPushButton::clicked, this, &MyWidget::ClassOver); //点击按钮,触发信号
connect(te, teacherSignal, st, studentSlot); //信号去触发槽函数
}
void MyWidget::ClassOver()
{
//下课后,老师触发饿了的信号
emit te->hungry("鱼香肉丝");
}
//MyWidget.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QtWidgets/QWidget>
#include "ui_MyWidget.h"
#include "Teacher.h"
#include "Student.h"
#include <QPushButton>
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = Q_NULLPTR);
private:
Ui::MyWidgetClass ui;
void ClassOver();
Teacher *te;
Student *st;
QPushButton *bt;
};
4.2 没有参数情况下
断开信号槽连接:disconnect();
例如:disconnect(te, teacherSignal2, st, studentSlot2);
//MyWidget.cpp
#include "MyWidget.h"
#include <QHBoxLayout>
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
bt = new QPushButton("下课",this);
QHBoxLayout *ly = new QHBoxLayout(this);
ly->addStretch();
ly->addWidget(bt);
ly->addStretch();
//创建老师对象
te = new Teacher(this);
//创建学生对象
st = new Student(this);
//定义函数指针
void (Teacher:: *teacherSignal2)(void) = &Teacher::hungry;
void (Student:: *studentSlot2)(void) = &Student::treat;
//信号槽绑定
connect(bt, &QPushButton::clicked, te, teacherSignal2); //点击按钮,触发信号函数
connect(te, teacherSignal2, st, studentSlot2); //信号函数去响应槽函数
}
void MyWidget::ClassOver()
{
//下课后,老师触发饿了的信号
emit te->hungry();
}
(5)一个信号可以连接多个槽函数
//信号槽绑定
connect(bt, &QPushButton::clicked, te, teacherSignal2); //点击按钮,触发信号
connect(te, teacherSignal2, st, studentSlot2); //信号函数去响应槽函数
connect(bt, &QPushButton::clicked, this, &QWidget::close); //点击按钮同时关闭窗口
(6)多个按钮连接一个槽函数
//信号槽绑定
connect(bt1, &QPushButton::clicked, te, teacherSignal2); //点击按钮,触发信号
connect(te, teacherSignal2, st, studentSlot2); //信号去响应曹函数
connect(bt1, &QPushButton::clicked, this, &QWidget::close);
connect(bt2, &QPushButton::clicked, te, teacherSignal2); //点击按钮,触发信号
connect(te, teacherSignal2, st, studentSlot2); //信号去响应曹函数
connect(bt2, &QPushButton::clicked, this, &QWidget::close);