信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。
connect()函数最常用的一般形式:
connect(sender, signal, receiver, slot);
参数解释:
sender:发出信号的对象
signal:发送对象发出的信号
receiver:接收信号的对象
slot:接收对象在接收到信号之后所需要调用的函数(槽函数)
系统自带的信号有如下几个
void clicked(bool checked = false)
void pressed()
void released()
void toggled(bool checked )
signals inherited from Qwidget
signals inherited from Q0bject
使用connect()可以让我们连接系统提供的信号和槽。但是,Qt 的信号槽机制并不仅仅是使用系统提供的那部分,还会允许我们自己设计自己的信号和槽。
下面看看使用 Qt 的信号槽:
signals:
void hungury();
public slots:
void treat();
void MyWidget::ClassIsOver()
{
//发送信号
emit teacher->hungury();
}
//自定义槽函数 实现
void Student::eat()
{
qDebug() << "该吃饭了!";
}
teacher = new Teacher(this);
student = new Student(this);
connect(teacher,&Teacher::hungury,student,&Student::treat);
并且调用下课函数,测试打印出 “该吃饭了”
void hungury(QString name); 自定义信号
void treat(QString name ); 自定义槽
void (Teacher:: * teacherSingal)(QString) = &Teacher::hungury;
void (Student:: * studentSlot)(QString) = &Student::treat;
connect(teacher,teacherSingal,student,studentSlot);
自定义信号槽需要注意的事项:
student.h
#ifndef STUDENT_H
#define STUDENT_H
#include
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
signals:
public slots:
//早期Qt版本,必须要写到public slots 下,高级版本可以写到 public或者全局下
//返回值 void,需要声明,也需要实现
//可以有参数,可以发生重载
void treat(); // treat 请客的意思
void treat(QString foodName);
};
#endif // STUDENT_H
teacher.h
#ifndef TEACHER_H
#define TEACHER_H
#include
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
signals:
// 自定义信号,写道signals下
// 返回值是void 只需要声明,不需要实现
// 可以有参数,可以重载
void hungry();
void hungry(QString foodName);
public slots:
};
#endif // TEACHER_H
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
#include"teacher.h"
#include"student.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
Teacher * zt;
Student * st;
void classIsOver();
};
#endif // WIDGET_H
student.cpp
#include "student.h"
#include
Student::Student(QObject *parent) : QObject(parent)
{
}
void Student::treat()
{
qDebug()<<"请老师吃饭";
}
void Student::treat(QString foodName)
{
//qDebug()<<"请老师吃饭,老师要吃:"<
// 即 宫保鸡丁 旁边会有引号显示出来
//若想去掉引号 需要将变量的QString型 转化为 char *型 先转成QByteArray(.toUtf8()) 再转char *(.data())
qDebug()<<"请老师吃饭,老师要吃:"<<foodName.toUtf8().data(); //这样就没有引号了
}
teacher.cpp
#include "teacher.h"
Teacher::Teacher(QObject *parent) : QObject(parent)
{
}
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include
#include
//Teacher 类 老师类
//Student 类 学生类
//下课后,老师会触发一个信号,饿了,学生相应信号,请客吃饭
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);
// //先用 connect 将老师和学生信号连接起来,再调用下课函数 使老师发出触发信号
// //调用下课函数
// classIsOver();
//连接带参数的信号和槽
//指针->地址 函数指针->函数地址
//函数指针:函数返回值类型(*指针变量名)(函数参数列表)
void(Teacher::*teacherSignal)(QString)=&Teacher::hungry;
void(Student::*studentSlot)(QString)=&Student::treat;
connect(zt,teacherSignal,st,studentSlot);
// classIsOver(); //此函数使老师发出 饿了信号
//点击一个 下课的按钮,再触发下课
QPushButton * btn1 =new QPushButton("下课",this);
this->resize(600,400); //重置窗口大小
//点击按钮 触发下课
// connect(btn,&QPushButton::clicked,this,&Widget::classIsOver);
/* //无参信号和槽连接
void(Teacher::*teacherSignal2)(void)=&Teacher::hungry;
void(Student::*studentSlot2)(void)=&Student::treat;
connect(zt,teacherSignal2,st,studentSlot2); //老师发出饿了信号后 学生做出反应
*/
//信号连接信号
// connect(btn,&QPushButton::clicked,zt,teacherSignal2); //点击按钮后 老师响应饿了的信号
//断开信号
// disconnect(zt,teacherSignal2,st,studentSlot2); //此行代码可以断开 老师和同学之间的连接信号
//即老师发出饿了信号后,学生不会做出反应
//Lambda表达式
/* QPushButton *btn3=new QPushButton("Over",this);
btn3->move(100,0);
[btn](){ //[]里面只添加了btn 表示下面{}里只会识别到btn的相关操作
btn->setText("aaaa");
// btn3->setText("bbbb"); //识别不到
}(); //最后面加一个() 表示调用此表达式
*/
//mutable关键字 用于修饰值传递的变量,修改的是拷贝,而不是本体
/* QPushButton *mybtn=new QPushButton("one",this);
QPushButton *mybtn2=new QPushButton("two",this);
mybtn->move(100,0);
mybtn2->move(100,100);
int m=10;
connect(mybtn,&QPushButton::clicked,this,[m]()mutable{m=100+10;qDebug()<
// int ret=[]()->int{return 1000;}();
// qDebug()<<"ret = "<
//利用Lambda表达式 实现点击按钮 关闭窗口 最常用的表达式是: [=](){}
QPushButton *btn2=new QPushButton("关闭",this);
btn2->move(100,0);
connect(btn2,&QPushButton::clicked,this,[=](){
// this->close(); //关闭窗口
emit zt->hungry("宫保鸡丁"); //点击“关闭”按钮 触发老师饿了信号
});
}
void Widget::classIsOver()
{
//下课函数,调用后 出发老师饿了的信号
//emit zt->hungry(); //emit 触发自定义信号关键字
emit zt->hungry("宫保鸡丁");
}
Widget::~Widget()
{
delete ui;
}
main.cpp
#include "widget.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}