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?

新战场:https://blog.csdn.net/Stephen___Qin
原文地址:https://www.cnblogs.com/Stephen-Qin/p/13053138.html