qt之信号与槽

目录

信号与槽的介绍  

系统自带的信号和槽

自定义信号槽

Qt4版本的连接方式

lambda表达式的连接方式


信号与槽的介绍  

  信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

系统自带的信号和槽

  下面我们完成一个小功能,上面我们已经学习了按钮的创建,但是还没有体现出按钮的功能,按钮最大的功能也就是点击后触发一些事情,比如我们点击按钮,就把当前的窗口给关闭掉,那么在Qt中,这样的功能如何实现呢?

其实无法两行代码就可以搞定了,我们看下面的代码

  QPushButton * quitBtn = new QPushButton("关闭窗口",this);

  connect(quitBtn,&QPushButton::clicked,this,&MyWidget::close);

第一行是创建一个关闭按钮,这个之前已经学过,第二行就是核心了,也就是信号槽的使用方式

connect()函数最常用的一般形式:

connect(sender, signal, receiver, slot);

参数解释:

    1. sender:发出信号的对象
    2. signal:发送对象发出的信号
    3. receiver:接收信号的对象
    4. slot:接收对象在接收到信号之后所需要调用的函数(槽函数)

那么系统自带的信号和槽通常如何查找呢,这个就需要利用帮助文档了,在帮助文档中比如我们上面的按钮的点击信号,在帮助文档中输入QPushButton,首先我们可以在Contents中寻找关键字 signals,信号的意思,但是我们发现并没有找到,这时候我们应该想到也许这个信号的被父类继承下来的,因此我们去他的父类QAbstractButton中就可以找到该关键字,点击signals索引到系统自带的信号有如下几个

 这里的clicked就是我们要找到,槽函数的寻找方式和信号一样,只不过他的关键字是slot。

自定义信号槽

  使用connect()可以让我们连接系统提供的信号和槽。但是,Qt 的信号槽机制并不仅仅是使用系统提供的那部分,还会允许我们自己设计自己的信号和槽。

  这边我们设计一个场景:

Teacher类 老师类
Student类 学生类
下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭

老师类

#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

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


#include "teacher.h"

Teacher::Teacher(QObject *parent) : QObject(parent)
{

}

 学生类

#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class Student : public QObject
{
    Q_OBJECT
public:
    explicit Student(QObject *parent = nullptr);

signals:

public slots:
    //早期Qt版本必须要写到public slots,高级版本可以写到public或者全局下
    //返回值是void,需要声明也需要实现
    //可以有参数,可以发送重载
    void treat();

    void treat(QString foodName);
};

#endif // STUDENT_H


#include "student.h"
#include <QDebug>
Student::Student(QObject *parent) : QObject(parent)
{

}

void Student::treat()
{
    qDebug()<<"请老师吃饭";
}

void Student::treat(QString foodName)
{
    //QString->char *
    qDebug()<<"请老师吃饭,老师要吃"<<foodName.toUtf8().data();
}

这边需要注意的是定义信号只需要定义不需要实现,而槽函数既需要定义又需要实现

槽函数的连接也只需要使用connect函数连接信号与槽即可

//    connect(zt,&Teacher::hungry,st,&Student::treat);

这边需要注意的是信号与槽可以重载,当信号与槽重载后需要用函数指针的方式来存放函数地址,否则编译器会不知道是与哪个函数连接导致报错。

    //指针->地址
    //函数指针->函数地址
    void(Teacher::*teacherSignal)(QString) = &Teacher::hungry;

    void(Student::*studentSLot)(QString)=&Student::treat;
    connect(zt,teacherSignal,st,studentSLot);

需要注意的是

1、信号是可以连接信号的

2、一个信号可以连接多个槽函数

3、多个信号可以连接一个槽函数

4、信号和槽函数的参数必须类型一一对应

5、信号和槽的参数个数,信号的参数个数可以多于槽函数的参数个数

Qt4版本的连接方式

connect(zt,SIGNAL(hungry(QString)),st,SLOT(treat(QString)));

这里使用了SIGNAL和SLOT这两个宏,将两个函数名转换成了字符串。注意到connect()函数的 signal 和 slot 都是接受字符串,一旦出现连接不成功的情况,Qt4是没有编译错误的(因为一切都是字符串,编译期是不检查字符串是否匹配),而是在运行时给出错误。这无疑会增加程序的不稳定性。

Qt5在语法上完全兼容Qt4,而反之是不可以的。

lambda表达式的连接方式

还有一种方式是利用lambda表达式的方式来进行连接信号和槽。

首先看一下Lambda表达式的基本构成:

[capture](parameters) mutable ->return-type

{

statement

}

[函数对象参数](操作符重载函数参数)mutable ->返回值{函数体}

① 函数对象参数;

[],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:

    1. 空。没有使用任何函数对象参数。
    2. =。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
    3. &。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
    4. this。函数体内可以使用Lambda所在类中的成员变量。
    5. a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
    6. &a。将a按引用进行传递。
    7. a, &b。将a按值进行传递,b按引用进行传递。
    8. =,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。
    9. &, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。

② 操作符重载函数参数;

标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。

③ 可修改标示符;

mutable声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。

由于lambda表达式是c++11标准中新出现的方式,所以需要在.pro文件中加入c++11的标准

 

 

猜你喜欢

转载自blog.csdn.net/qq_45526401/article/details/128908492