一.什么是信号和槽函数
QT中通过信号(signal)和槽函数(slot)将事件和响应函数连接起来(可以类比MFC中的操作和对应的On开头的响应函数).
它的优点在于信号和槽函数是松耦合的关系,你可以通过connect将两者连接起来,也可以通过disconnect将两者断开.
它们的格式如下:
connect/disconnect(信号的发送者, 具体的信号, 信号的接收者, 信号的处理(槽)).
二.信号和槽函数的例子
假如有这样一个需求:在下课的时候,老师说饿了,然后学生去请老师吃饭.
这样对应到信号和槽函数,如下所示:
设计的类图如下所示:
在widget.cpp中有如下的代码组织,其中讨论了有无函数重载的情况下对应的实现;信号连接信号的用法;断开连接;用Lambda表达式来表示槽函数的方式.
#include "widget.h" #include <QPushButton> Widget::Widget(QWidget *parent) : QWidget(parent) { this->te = new Teacher(this); this->st = new Student(this); ///无参信号和槽 //当不存在函数重载时,可以直接使用&Teacher::hungry的方式 //connect(te, &Teacher::hungry, st, &Student::treat); //classIsOverNoFoodName(); //也可以如此触发:te->hungry(); //当存在函数重载时,需要使用函数指针. void(Teacher:: * teacherSignalVoid)(void) = &Teacher::hungry; void(Student:: * studentSlotVoid)(void) = &Student::treat; connect(te, teacherSignalVoid, st, studentSlotVoid); classIsOverNoFoodName(); //也可以如此触发:te->hungry(); ///带参数的信号和槽(如果带参数的函数不存在重载问题,可以直接使用最简单的connect方式,就像无参的那个例子一样.) //函数指针 -> 函数地址 void(Teacher:: * teacherSignal)(QString) = &Teacher::hungry; //这里的函数指针要指明它是作用域,它是Teacher类下的,不是别的下面的. void(Student:: * studentSlot)(QString) = &Student::treat; connect(te, teacherSignal, st, studentSlot); classIsOver(); ///点击按钮来触发下课 QPushButton * btn = new QPushButton("classIsOver", this); btn->move(100,100); this->setFixedSize(600, 300); this->setWindowTitle("signalAndSlotDemo"); //这里把一般的函数也可以作为槽函数来使用. //connect(btn, &QPushButton::clicked, this, &Widget::classIsOver); ///信号连接信号 //!注意,这里的clicked原型是clicked(bool checked = false),它有一个bool参数,作为它的槽函数要么是一个bool参数,要么是没有参数(即为void); connect(btn, &QPushButton::clicked, te, teacherSignalVoid); //此处因为hungry有重载的问题,所以不能够直接使用Teacher::hungry. ///断开信号 //disconnect(te, teacherSignalVoid, st, studentSlotVoid); //disconnect(btn, &QPushButton::clicked, te, teacherSignalVoid); //!!!!!!拓展!!!!!!!!!! //!!Qt4版本以前连接方式: //无参版本: //connect(te, SIGNAL(hungry(), st, SLOT(treat()); //优点:参数直观. 缺点:类型不做检测. ///Lambda表达式:匿名函数,简便书写. [=](){ //=:值传递 btn->setText("lambda"); }(); //加上后面的()才能算是执行函数 ///利用Lambda表达式实现点击按钮关闭窗口 connect(btn, &QPushButton::clicked, this, [=](){ this->close(); }); } Widget::~Widget() { } void Widget::classIsOver() { emit te->hungry("kongpochicken"); } void Widget::classIsOverNoFoodName() { emit te->hungry(); }
完整的代码位置:https://github.com/StephennQin/QTProjects/tree/master/02_signalAndSlot
三.信号和槽函数的总结
1.信号是可以连接信号
2.一个信号可以连接多个槽函数
3.多个信号 可以连接 同一个槽函数.
4.信号和槽函数的参数 必须类型一一对应,就像信号里传递的是QString类型的"宫保鸡丁",那么槽函数里也要用QString类型的foodName来接收.
5.信号的参数个数可以多于槽函数参数个数.比如上面的clicked原型是clicked(bool checked = false),它有一个bool参数,作为它的槽函数要么是一个bool参数,要么是没有参数(即为void);
--------------------------------------------------------------------------------------------------------------------
文章总结自bilibili上的传智播客的视频: https://www.bilibili.com/video/BV1g4411H78N?