• 【QT】信号和槽


    img

    一、前置示例代码

    1. main.cpp
    #include "widget.h"
    
    #include 
    
    // argc, argv 接收的是鼠标和键盘的命令,传递给QApplication 对象。
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);		// 应用程序对象a,在Qt中,应用程序对象,有且仅有一个。
        Widget w;						// 窗口对象w, Widget 父类-> QWidget
        w.show();						// 窗口对象w, 默认不会显示,必须调用show方法显示窗口。
        return a.exec();				// 让应用程序对象a,进入消息循环-->  while(true);
    
    //    while(true)
    //    {
    //        if(点击叉子)
    //        {
    //            break;
    //        }
    //    }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    argc, argv 接收的是鼠标和键盘的命令,传递给QApplication 对象。


    1. widget.h
    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include 
    
    class Widget : public QWidget
    {
        Q_OBJECT	//宏,允许类中使用信号和槽的机制。
    
    public:
        Widget(QWidget *parent = nullptr);
        ~Widget();
    
    signals:
        void isSignal(int signal = 0);
    public slots:
        void isSlot(int slot);
    
    };
    #endif // WIDGET_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    Q_OBJECT 宏,允许类中使用信号和槽的机制。


    1. widget.cpp
    #include "widget.h"
    #include 
    
    Widget::Widget(QWidget *parent) : QWidget(parent)
    {
        // 信号和槽的绑定:
        connect(this, &Widget::isSignal, this, &Widget::isSlot);
    
        // 发送信号:
        emit isSignal(1);
    }
    
    Widget::~Widget()
    {
    }
    
    
    // 槽函数的实现:
    void Widget::isSlot(int slot){
        QString qString;
        qDebug()<< "我是槽函数,我收到的信号是:" << qString.number(slot);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    程序输出:

    我是槽函数,我收到的信号是: "1"
    
    • 1

    注意:我们并没有直接给槽函数的变量 slot 赋值。 ==槽函数的slot的值,是从信号的signal传递而来的==。




    二、信号槽如何传递参数

    1. 信号和槽函数的参数,类型必须进行一一对应,如信号的参数为int,槽函数的参数也为int。

    信号:

    signals:
        void isSignal(int signal = 0);
    
    • 1
    • 2

    槽的定义:

    public slots:
        void isSlot(int slot);
    
    • 1
    • 2

    槽的实现:

    void Widget::isSlot(int slot){
        QString qString;
        qDebug()<< "我是槽函数,我收到的信号是:" << qString.number(slot);
    }
    
    • 1
    • 2
    • 3
    • 4

    发送信号:

    emit isSignal(1);
    
    • 1

    程序输出:

    我是槽函数,我收到的信号是: "1"
    
    • 1

    可以看出,当信号发送后,信号函数的signal参数值 “ 1” ,已经成功传递给 槽函数的 接收变量 slot, slot = 1。



    1. 当信号的参数与槽函数的参数数量不同时,只能是信号的参数数量,多于槽函数的参数数量,且前面相同数量的参数类型应一致,信号中多余的参数会被忽略。

    信号:

    signals:
        void isSignal(int signal = 0, QString s = "我是信号");
    
    • 1
    • 2

    槽的定义:

    public slots:
        void isSlot(int slot);
    
    • 1
    • 2

    槽的实现:

    void Widget::isSlot(int slot){
        QString qString;
        qDebug()<< "我是槽函数,我收到的信号是:" << qString.number(slot);
    }
    
    • 1
    • 2
    • 3
    • 4

    发送信号:

    emit isSignal(2, "你好");
    
    • 1

    程序输出:

    我是槽函数,我收到的信号是: "2"
    
    • 1

    可以看出,当信号发送后,信号函数的signal 的参数值 “ 2” ,被成功传递给 槽函数的 接收变量 slot, slot = 2。而 s = “你好” 被忽略。




    三、信号和槽发生重载

    1. teacher.h
    signals:
        void hungry();
    
        void hungry(QString foodName);
    
    • 1
    • 2
    • 3
    • 4

    1. student.h && student.cpp
    public slots:
        void treat();
    
        void treat(QString foodName);
    
    
        
    void Student::treat(){
        qDebug()<<"请老师吃饭";
    }
    
    void Student::treat(QString foodName){
         qDebug()<<"请老师吃饭,吃:" << foodName.toUtf8().data();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1. widget.h
    #include "teacher.h"
    #include "student.h"
    
    class Widget : public QWidget
    {
    public:
        Teacher * ls;
        Student * st;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    1. widget.cpp
    #include "widget.h"
    #include 
    #include 
    
    //Teacher类 老师类
    //student类 学生类
    //下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭
    
    
    Widget::Widget(QWidget *parent) : QWidget(parent)
    {
        //创建一个老师对象
        this->ls = new Teacher(this);
        //创建一个学生对象
        this->st = new Student(this);
    
         //连接无参数的信号和槽--1
        void (Teacher:: * teacherSignal_void)(void) = &Teacher::hungry;
        void (Student:: * studentSlot_void)(void) = &Student::treat;
        connect(ls,teacherSignal_void,st,studentSlot_void);
        emit ls->hungry();
    
        qDebug()<<"---------------";
    
        //连接带参数的信号和槽--2
        void (Teacher:: * teacherSignal)(QString) = &Teacher::hungry;
        void (Student:: * studentSlot)(QString) = &Student::treat;
        connect(ls,teacherSignal,st,studentSlot);
        emit ls->hungry("宫爆鸡丁");
    }
    
    Widget::~Widget()
    {
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    程序输出:

    请老师吃饭
    ---------------
    请老师吃饭,吃: 宫爆鸡丁
    
    • 1
    • 2
    • 3

    此外,我们可以通过setParent函数为 QObject 对象设置一个父对象

    //创建一个老师对象
    this->ls = new Teacher(this);
    //创建一个学生对象
    this->st = new Student(this);
    
    • 1
    • 2
    • 3
    • 4

    当父对象被析构时,它会自动析构其所有的子对象。这意味着无需手动管理子对象的销毁,减轻了开发人员的负担,并确保在不再需要这些子对象时,它们会被正确地释放。




    四、QT4版本以前的信号和槽的连接方式

    底层SIGNAL( ““hungry”” ),SLOT( “treat” )

    connect(  zt, SIGNAL( hungry() ), st, SLOT( treat() )  );
    
    • 1

    优点:参数直观,缺点:类型不做检测。



    五、信号与槽的参数不对应–使用Lambda表达式

    widget.cpp

    #include "widget.h"
    #include 
    #include 
     
    //Teacher类 老师类
    //student类 学生类
    //下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭
     
     
    Widget::Widget(QWidget *parent) : QWidget(parent)
    {
        //创建一个老师对象
        this->zt = new Teacher(this);
        //创建一个学生对象
        this->st = new Student(this);
        //点击一个按钮,再进行下课
        QPushButton * btn = new QPushButton("下课",this);
        setFixedSize(600,400);
     
        //连接带参数的信号和槽
        //指针->地址,函数指针->函数地址
        void (Teacher::*teacherSignal)(QString) = &Teacher::hungry;
        void (Student::*studentSlot)(QString) = &Student::treat;
        connect(zt,teacherSignal,st,studentSlot);
     
        //信号连接信号 一个信号触发另一个信号
        //-----------------------------------------------------
     
        connect(btn,&QPushButton::clicked,zt,teacherSignal);
     
        //-----------------------------------------------------
    }
     
     
    Widget::~Widget()
    {   
    }
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    重点分析:

    Widget(QWidget *parent = nullptr);
    
    Widget::Widget(QWidget *parent) : QWidget(parent)
    {
    	QPushButton * btn = new QPushButton("下课",this);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    parent = 0 ,说明Widget是顶级窗口。·new QPushButton(this)·是让btn对象 依赖在 myWidget窗口中。

    程序报错:

    static assertion failed: Signal and slot arguments are not compatible
    
    • 1

    clicked信号的原型为:

    void clicked(bool checked = false)
    
    • 1

    hungry槽的原型为:

     void hungry(QString foodName);
    
    • 1

    原因为信号的参数与槽函数参数不对应。 bool型 和 QString 的类型不同。



    正确写法:

    connect(btn,&QPushButton::clicked,zt,teacherSignal);
    
    • 1

    改为:

    connect(btn,&QPushButton::clicked, this, [this](){
         emit ls->hungry("宫爆鸡丁");
    });
    
    • 1
    • 2
    • 3

    或:

    connect(btn,&QPushButton::clicked, [this](){
         emit this->ls->hungry("宫爆鸡丁");
    });
    
    • 1
    • 2
    • 3

    该connect只有三个参数,在三个参数情况下,默认第三个槽函数的对象是本类this,也就是第三个参数this被省略了。

    如果第三个参数是this,第四个参数是Lambda表达式,则可以省略第三个参数 this。

    个人实测,第三个参数写ls也行:

    connect(btn,&QPushButton::clicked, ls, [this](){
         emit ls->hungry("宫爆鸡丁");
    });
    
    • 1
    • 2
    • 3

    程序输出:

    请老师吃饭,吃: 宫爆鸡丁
    请老师吃饭,吃: 宫爆鸡丁
    请老师吃饭,吃: 宫爆鸡丁
    请老师吃饭,吃: 宫爆鸡丁
    
    • 1
    • 2
    • 3
    • 4




    参考连接:

    《Qt5:信号和槽使用示例》

    qt报错:static assertion failed: Signal and slot arguments are not compatible

    信号槽如何传递参数(或带参数的信号槽)

  • 相关阅读:
    生命在于学习——Stable Diffution(Mac端)
    python2.7和python3.8代码兼容中的问题汇总
    (六)Vue之MVVC
    机器学习原理汇总
    微信小程序仿QQ头像轮播效果
    Autosar基本概念详细介绍
    golang容易导致内存泄漏的几种情况
    大厂FPGA的面试题
    Ubuntu 安装 npm 和 node
    微信小程序里面使用wxs文件
  • 原文地址:https://blog.csdn.net/zsyyugong/article/details/134022341