QT的信號與槽函數


一.什么是信號和槽函數

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?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM