一.什么是信號和槽函數
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?