【QT】信号和槽

一、前置示例代码

  1. main.cpp
c 复制代码
#include "widget.h"

#include <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(1);
}
  1. widget.h
c 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

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. widget.cpp
c 复制代码
#include "widget.h"
#include <QDebug>

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"

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

二、信号槽如何传递参数

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

信号:

c 复制代码
signals:
    void isSignal(int signal = 0);

槽的定义:

c 复制代码
public slots:
    void isSlot(int slot);

槽的实现:

c 复制代码
void Widget::isSlot(int slot){
    QString qString;
    qDebug()<< "我是槽函数,我收到的信号是:" << qString.number(slot);
}

发送信号:

c 复制代码
emit isSignal(1);

程序输出:

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

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

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

信号:

c 复制代码
signals:
    void isSignal(int signal = 0, QString s = "我是信号");

槽的定义:

c 复制代码
public slots:
    void isSlot(int slot);

槽的实现:

c 复制代码
void Widget::isSlot(int slot){
    QString qString;
    qDebug()<< "我是槽函数,我收到的信号是:" << qString.number(slot);
}

发送信号:

c 复制代码
emit isSignal(2, "你好");

程序输出:

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

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

三、信号和槽发生重载

  1. teacher.h
c 复制代码
signals:
    void hungry();

    void hungry(QString foodName);
  1. student.h && student.cpp
c 复制代码
public slots:
    void treat();

    void treat(QString foodName);


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

void Student::treat(QString foodName){
     qDebug()<<"请老师吃饭,吃:" << foodName.toUtf8().data();
}
  1. widget.h
c 复制代码
#include "teacher.h"
#include "student.h"

class Widget : public QWidget
{
public:
    Teacher * ls;
    Student * st;
};
  1. widget.cpp
c 复制代码
#include "widget.h"
#include <QPushButton>
#include <QDebug>

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


Widget::Widget(QWidget *parent) : QWidget(parent)
{
    //创建一个老师对象
    this->ls = new Teacher(this);
    //创建一个学生对象
    this->st = new Student(this);

     //连接带参数的信号和槽--1
    void (Teacher:: * teacherSignal_void)() = &Teacher::hungry;
    void (Student:: * studentSlot_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()
{
}

程序输出:

请老师吃饭
---------------
请老师吃饭,吃: 宫爆鸡丁

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

c 复制代码
//创建一个老师对象
this->ls = new Teacher(this);
//创建一个学生对象
this->st = new Student(this);

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

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

widget.cpp

c 复制代码
#include "widget.h"
#include <QPushButton>
#include <QDebug>
 
//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()
{   
}
 

程序报错:

c 复制代码
static assertion failed: Signal and slot arguments are not compatible

clicked信号的原型为:

c 复制代码
void clicked(bool checked = false)

hungry槽的原型为:

c 复制代码
 void hungry(QString foodName);

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

正确写法:

c 复制代码
connect(btn,&QPushButton::clicked,zt,teacherSignal);

改为:

c 复制代码
connect(btn,&QPushButton::clicked, this, [this](){
     emit ls->hungry("宫爆鸡丁");
});

或:

c 复制代码
connect(btn,&QPushButton::clicked, [this](){
     emit this->ls->hungry("宫爆鸡丁");
});

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

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

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

c 复制代码
connect(btn,&QPushButton::clicked, ls, [this](){
     emit ls->hungry("宫爆鸡丁");
});

程序输出:

请老师吃饭,吃: 宫爆鸡丁
请老师吃饭,吃: 宫爆鸡丁
请老师吃饭,吃: 宫爆鸡丁
请老师吃饭,吃: 宫爆鸡丁

参考连接:

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

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

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

相关推荐
玉带湖水位记录员36 分钟前
命令模式——C++实现
c++·设计模式·命令模式
Zer0_on2 小时前
C++string类
开发语言·c++
Lenyiin2 小时前
02.01、移除重复节点
c++·算法·leetcode
阿正的梦工坊8 小时前
PyTorch到C++再到 CUDA 的调用链(C++ ATen 层) :以torch._amp_update_scale_调用为例
c++·人工智能·pytorch
微凉的衣柜9 小时前
【C++/CMake】从静态库到动态库:一行改动解决 “找不到 -ljsoncpp” 链接报错
开发语言·c++
bbqz00711 小时前
浅说c/c++ coroutine
c++·协程·移植·epoll·coroutine·libco·网络事件库·wepoll
~糖炒栗子~11 小时前
[Day 11]209.长度最小的子数组
数据结构·c++·算法·leetcode
zym大哥大12 小时前
C++11右值与列表初始化
数据结构·c++
Reoyy14 小时前
Visual Studio 2022安装教程
c++·ide·visual studio
执着的小火车15 小时前
【2024华为OD-E卷-100分-火星文计算】(题目+思路+Java&C++&Python解析)
java·数据结构·c++·算法·华为od·华为