QT信号槽机制以及自定义信号槽

1. 信号槽机制

1.1 信号槽简介

信号和槽是用于对象之间的通信的,这是 Qt 的核心。为此 Qt 引入了一些关键字,他们是slotssignalsemit,这些都不是 C++关键字,是 Qt 特有的,这些关键字会被 Qt 的 moc转换为标准的 C++语句。信号和槽其实是观察者模式的一种实现。

1.2 信号槽的白话理解

南昌起义:1927年8月1日,中共联合国民党左派,打响了武装反抗国民党反动派的第一枪,揭开了中国共产党独立领导武装斗争和创建革命军队的序幕。
8月1日2时,在周恩来、贺龙、叶挺、朱德、刘伯承的领导下,南昌起义开始。按照中共前委的作战计划,第20军第1、第2师向旧藩台衙门、大士院街、牛行车站等处守军发起进攻;第11军第24师向松柏巷天主教堂、新营房、百花洲等处守军发起进攻。激战至拂晓,全歼守军3000余人,缴获各种枪5000余支(挺),子弹70余万发,大炮数门。
当日下午,驻马回岭的第25师第73团全部、第75团3个营和第74团机枪连,在聂荣臻、周士第率领下起义,1927年8月2日到达南昌集中。
1927年8月2日,南昌市各界群众数万人集会,庆祝南昌起义的伟大胜利和革命委员会的成立。会后各界青年踊跃参军,仅报名的学生就有数百人。
请添加图片描述

1.3 信号槽格式

只有 QObject 及其派生类才能使用信号和槽机制,且在类之中还需要使用 Q_OBJECT 宏

1.3.1 信号需符合以下规则
💫 信号使用 signals 关键字声明,信号默认是 public 的;
💫 信号需要使用 emit 关键字发射;信号只需声明,不能对其进行定义,信号是由 moc 自动生成的;
💫 信号的返回值只能是 void 类型的。
1.3.2 声明槽需符合以下规则
💫 声明槽需要使用 slots 关键字,且槽需使用 public、private、protected 访问控制符之一;
💫 槽就是一个普通的函数,可以像使用普通函数一样进行使用,槽与普通函数的主要区别是:槽可以与信号关联。

因为信号位于类之中,因此发射信号的位置需要位于该类的成员函数中或该类能见到信号的标识符的位置。

1.3.3 信号和槽的关系
💫 槽的参数的类型需要与信号参数的类型相对应;
💫 一个信号可以与多个槽关联,多个信号也可以与同一个槽关联,信号也可以关联到另一个信号上;
💫 若一个信号关联到多个槽时,则发射信号时,槽函数按照关联的顺序依次执行;
💫 若信号连接到另一个信号,则当第一个信号发射时,会立即发射第二个信号。

1.4 信号和槽的关联(连接)

💫 C++ 连接信号槽 - Qt4 语法
connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(close()));

💫 C++ 连接信号槽 - Qt5 语法
connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::close);

💫 C++ 连接信号槽 - Lambda 表达式
connect(ui->pushButton, &QPushButton::clicked, this, [=](){ this->close(); });

2. 自定义信号槽

2.1 简单的自定义信号槽

设计一个老师类、一个学生类
老师饿了(信号)——>学生请客吃饭(槽函数响应)

目录结构:
请添加图片描述
student.h

#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

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

signals:

public slots:
    //早期Qt版本  必须写道public slots下   高版本Qt可以写到public或者全局下
    //需要声明   需要实现
    //可以有参数,可以发生重载
    void treat();
};

#endif // STUDENT_H

student.cpp

#include "student.h"
#include <QDebug>

Student::Student(QObject *parent) : QObject(parent)
{

}

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

teacher.h

#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

class Teacher : public QObject
{
    Q_OBJECT
public:
    explicit Teacher(QObject *parent = 0);

signals:
    void hungry();//自定义饿了信号

public slots:
};

#endif // TEACHER_H

teacher.cpp

#include "teacher.h"

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

}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "teacher.h"
#include "student.h"
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;

    Teacher *t;
    Student *s;

    void classisover();
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //创建一个老师对象
    t = new Teacher(this);

    //创建一个学生对象
    s = new Student(this);

    //老师饿了,学生请客吃饭连接
    connect(t,&Teacher::hungry,s,&Student::treat);

    //调用下课函数,发出信号
    classisover();

}

Widget::~Widget()
{
    delete ui;
}

void Widget::classisover()
{
    emit t->hungry();
}

运行结果:
请添加图片描述

2.2 槽函数重载解决办法

信号增加一个有参数的:
teacher.h

signals:
    void hungry();//自定义饿了信号

    void hungry(QString foodName);//添加一个菜名

槽函数增加一个有参数的:
student.h

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

    void treat(QString foodName);

运行报错,应用指针来说明是哪个信号,哪个槽函数
widget.cpp

//    //老师饿了,学生请客吃饭连接
//    connect(t,&Teacher::hungry,s,&Student::treat);

//    //调用下课函数,发出信号
//    classisover();
//第一种方法
    //连接带参数的信号槽
    //函数指针——>函数地址
    void(Teacher:: *hungrysignal) (QString) = &Teacher::hungry;
    void(Student:: *studentSlot) (QString) = &Student::treat;
    connect(t,hungrysignal,s,studentSlot);
    classisover();
//第二种方法
    connect(t, static_cast<void (Teacher:: *)(QString)>(&Teacher::hungry), s, static_cast<void (Student:: *)(QString)>(&Student::treat));
    classisover();

运行结果:
请添加图片描述
去掉引号:
student.cpp

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

运行结果:
请添加图片描述

2.3 信号连接信号案例

widget.h

private:
    Ui::Widget *ui;

    Teacher *t;
    Student *s;

    QPushButton *btn;

    void classisover();

widget.cpp

    btn = new QPushButton("下课", this);

//    connect(btn,&QPushButton::clicked,this,&Widget::classisover);

//    //老师饿了,学生请客吃饭连接
//    connect(t,&Teacher::hungry,s,&Student::treat);

//    //调用下课函数,发出信号
//    classisover();

    //连接带参数的信号槽
    //函数指针——>函数地址
//    void(Teacher:: *hungrysignal) (QString) = &Teacher::hungry;
//    void(Student:: *studentSlot) (QString) = &Student::treat;
//    connect(t,hungrysignal,s,studentSlot);

//连接无参数的信号槽
    void(Teacher:: *hungrysignal2) (void) = &Teacher::hungry;
    void(Student:: *studentSlot2) (void) = &Student::treat;
    connect(t,hungrysignal2,s,studentSlot2);


    connect(btn,&QPushButton::clicked,t,hungrysignal2);
//    classisover();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在QT中,我们可以使用信号机制来传递自定义类。首先,我们需要在类定义的头文件中使用Q_DECLARE_METATYPE宏来注册自定义类为元对象。然后,我们可以在信号函数中使用QVariant类来打包和解包自定义类的对象。 在发送端,我们可以创建自定义类的对象,并使用QVariant::fromValue函数将其打包为QVariant类型。然后,使用emit关键字发出带有打包对象的信号。 在接收端,我们需要在函数中获取传递的参数,并使用canConvert函数检查参数是否可以转换为自定义类。如果可以转换,我们可以使用value函数将其转换为自定义类对象,并进行后续操作。 总结来说,通过使用QVariant打包和解包自定义类对象,我们可以在QT中实现自定义类的信号传递。这种方式方便灵活,使得我们可以在应用程序中传递和处理自定义类的对象。12 #### 引用[.reference_title] - *1* [Qt信号传递自定义数据类型](https://blog.csdn.net/qq_40272495/article/details/105708632)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] - *2* [Qt信号传递自定义结构体](https://blog.csdn.net/lsyrhz/article/details/118439494)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值