Qt开发-信号和槽机制

上文链接(Qt开发-“Hello World”-2)

Qt信号和槽机制

信号和槽机制是Qt引以为豪的机制之一。所谓信号和槽,比如按钮被触发,会发出一个对应的按钮被触发的信号(signal),这种信号类似于水波纹传播没有任何方向性;当某个对象对该信号感兴趣时,就通过连接(connect)函数将此信号和对于发生此信号的处理槽(slot)函数绑定来处理发生的信号

示例

实现点击信号和槽按钮,窗口关闭
创建Qt Widgets Application桌面应用程序,项目名命名为“signal2slot”:
在这里插入图片描述
在signal2slot.cpp中输入如下代码:

#include "signal2slot.h"
#include "ui_signal2slot.h"

//包含QPushButton类
#include <QPushButton>

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

    // 重新指定窗口大小
    this->resize(400,200);
    // 固定窗口显示大小尺寸
    this->setFixedSize(400,200);
    // 设置窗口标题
    this->setWindowTitle("信号和槽");

    // 创建一个按钮
    QPushButton *btn0 = new QPushButton;
    // 设置其父类
    btn0->setParent(this);
    // 设置按钮文字
    btn0->setText("信号和槽");
    // 设置按钮位置
    btn0->move(160,80);

    // 信号和槽连接函数
    connect(btn0,&QPushButton::clicked,this,&Signal2Slot::close);
}

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

运行结果:点击信号和槽按钮,窗口关闭

主要涉及到两个知识点:

Qt应用程序中以左上角为坐标原点(0,0),向右为X轴正方向,向下为Y轴正方向
connect函数的一般形式为:connect(sender, signal, receiver, slot);

  1. sender:发出信号的对象
  2. signal:发送对象发出的信号
  3. receiver:接收信号的对象
  4. slot:接收对象在接收到信号之后所需要调用的函数(槽函数)
    上面实现的是Qt系统自带的信号和槽,可以在帮助文档中搜到相关信息:
    在这里插入图片描述
    Qt还能自定义信号和槽:
    实现过年了,小朋友来我家玩,我要发压岁钱
    清空signal2slot.cpp中之前敲入的代码:
#include "signal2slot.h"
#include "ui_signal2slot.h"

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

}

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

创建child和me类:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在child.h中添加拜年信号,信号需要添加到signals下:

#ifndef CHILD_H
#define CHILD_H

#include <QObject>

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

signals:
    void baiNian();

};

#endif // CHILD_H

在me.h中添加发红包槽函数,槽函数需要添加到public slots下:

#ifndef ME_H
#define ME_H

#include <QObject>

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

signals:

public slots:
    void faHongBao();

};

#endif // ME_H

在signal2slot.h中创建我和孩子类以及过年了这个触发条件:

#ifndef ME_H
#define ME_H

#include <QObject>

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

signals:

public slots:
    void faHongBao();

};

#endif // ME_H

在me.cpp中添加发红包这个槽函数的实现代码:

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

Me::Me(QObject *parent) : QObject(parent)
{

}

void Me::faHongBao()
{
    qDebug() << "我要发红包";
}

在signal2slot.cpp中初始化对象以及连接信号和槽函数,用emit触发自定义信号:

#include "signal2slot.h"
#include "ui_signal2slot.h"

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

    //创建一个小朋友对象
    this->child = new Child(this);
    //创建一个我对象
    this->me = new Me(this);

    //连接
    connect(child,&Child::baiNian,me,&Me::faHongBao);

    guoNianLe();

}

//过年了的方法
void Signal2Slot::guoNianLe()
{
    emit child->baiNian();
}

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


运行后会在调试窗口看到输出“我要发红包”字样
当自定义信号和槽出现重载的时候,利用函数指针,来明确指向哪个函数的地址:
child.h中添加重载信号函数:

#ifndef CHILD_H
#define CHILD_H

#include <QObject>

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

signals:
    void baiNian();
    void baiNian(QString money);

};

#endif // CHILD_H

me.h中添加重载槽函数:

#ifndef ME_H
#define ME_H

#include <QObject>

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

signals:

public slots:
    void faHongBao();
    void faHongBao(QString money);

};

#endif // ME_H

在me.cpp中实现重载槽函数:

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

Me::Me(QObject *parent) : QObject(parent)
{

}

void Me::faHongBao()
{
    qDebug() << "我要发红包";
}

void Me::faHongBao(QString money)
{
    qDebug() << "我要发" << money.toUtf8().data() << "红包";
}

signal2slot.cpp中实现重载信号和重载槽函数的连接:

#include "signal2slot.h"
#include "ui_signal2slot.h"

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

    //创建一个小朋友对象
    this->child = new Child(this);
    //创建一个我对象
    this->me = new Me(this);

//    //连接
//    connect(child,&Child::baiNian,me,&Me::faHongBao);

    //用函数指针指向函数地址解决重载问题
    void(Child:: *baiNianSignal)(QString) = &Child::baiNian;
    void(Me:: *faHongBaoSlot)(QString) = &Me::faHongBao;

    connect(child,baiNianSignal,me,faHongBaoSlot);

    guoNianLe();
}

//过年了的方法
void Signal2Slot::guoNianLe()
{
    emit child->baiNian("1000元");
}

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

运行后会在调试窗口看到输出“我要发1000元红包”字样
总结:

  1. 自定义的信号需要声明,不需要实现,可以有参数
  2. 自定义的槽函数需要声明,需要实现,可以有参数
  3. 用emit触发自定义信号
  4. 当自定义信号和槽出现重载的时候,利用函数指针,来明确指向哪个函数的地址
  5. 信号和槽的参数必须一一对应,参数个数不一定一一对应;信号的参数可以多余槽的参数,但是类型必须一一对应
  6. 信号可以连接信号
  7. 一个信号可以触发多个槽函数
  8. 信号和槽可以断开—disconnect
  9. 多个信号可以连接同一个槽函数
  10. 所有new出来的对象不用手动去释放,只要指定好父类;原因是children表中的对象会在窗口关闭后自动释放
发布了9 篇原创文章 · 获赞 14 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_36788698/article/details/104107283