【QT开发笔记-基础篇】| 第一章 QT入门 | 1.6 自定义信号槽

本节对应的视频讲解:B_站_链_接

https://www.bilibili.com/video/BV1gA4y1d7gz


上节课,我们讲解了标准信号槽,标准信号槽中,信号和槽函数,都是 Qt 框架定义好的。

Qt 还允许我们自定义信号和槽。

自定义信号和槽的条件:

  • 自定义的类,要继承自 QObject
  • 自定义的类,其中要声明一个宏 Q_OBJECT

只有满足了这两个条件才可以正常使用信号槽机制(当然,槽函数是全局函数、 Lambda 表达式等无需接收者的时候除外,后边讲解)。


1. 自定义信号槽案例


接下来,我们通过一个案例,演示自定义信号槽的使用。

案例:“长官” (Commander)发送一个 “冲” (go) 的信号,然后 “士兵" (Soldier)执行“ 战斗” (fight) 的槽函数


1.1 创建 Commander 类

在左侧项目文件名上右键 -> 添加新文件:
添加新文件

指定类名和父类
指定类名和父类

点击完成,即可添加cpp和.h文件到项目中
添加文件到项目

创建完成之后的 commander.cppcommander.h 文件,内容如下:

// commander.h
#ifndef COMMANDER_H
#define COMMANDER_H

#include <QObject>

// 1.自定义的类,需要继承自 QObject 类
class Commander : public QObject
{
    // 2.并且添加 Q_OBJECT 宏,才能正常使用 Qt 的信号和槽机制
    Q_OBJECT
public:
    explicit Commander(QObject *parent = nullptr);
// 3.在 signals 后面添加自定义的信号即可
signals:

};

#endif // COMMANDER_H

// commander.cpp
#include "commander.h"

Commander::Commander(QObject *parent)
    : QObject{parent}
{

}

1.2 添加自定义信号

signals 下面添加自定义的信号即可

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

signals:
    // 1.信号只需声明,无需实现
    // 2.信号返回值为 void
    void go();
};

1.3 添加 Soldier 类

按照同样的方法,添加 Soldier 类,创建完成之后的 soldier.hsoldier.cpp 文件,内容如下:

// soldier.h
#ifndef SOLDIER_H
#define SOLDIER_H

#include <QObject>

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

signals:

};

#endif // SOLDIER_H

// soldier.cpp
#include "soldier.h"

Soldier::Soldier(QObject *parent)
    : QObject{parent}
{

}

1.4 添加自定义槽

Soldier 士兵类,需要实现一个 fight 的槽函数

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

signals:

// 1.通常将槽函数添加到 slots 后面
// 这个 slots 也可以不写。不过建议写上,以指明这是一个槽函数
// pulic,表示槽函数既可以在当前类及其子类的成员函数中调用,也可以在类外部的其它函数(比如 main() 函数)中调用
public slots:
   // 2.槽函数的返回值和参数,要和信号保持一致
   // 由于信号无返回值,因此槽函数也无返回值
   // 由于信号无参数,因此槽函数也无参数
   void fight();
};

soldier.h 文件中有了槽函数的声明,还需要在 soldier.cpp 中实现

可以在槽函数声明处,直接按 alt + enter 快捷键,快速生成函数定义

void Soldier::fight()
{
    qDebug() << "fight";
}

1.5 连接自定义的信号和槽

信号和槽都已经定义完毕, 接下来就可以进行连接了

mainwindow.cpp 中,定义 CommanderSoldier 类的实例,并建立信号和槽的连接,如下:

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

    // 1. 创建两个类的实例
    Commander commander;
    Soldier soldier;

    // 2. 建立信号和槽的连接
    connect(&commander, SIGNAL(go()), &soldier, SLOT(fight()));

    // 3. 发送信号
    // emit 可省略
    /*emit*/commander.go();
}

这样,在程序执行后,就可以在【应用程序输出】窗口看到槽函数执行的结果了:
执行结果


1.6 信号和槽的重载

我们知道,信号和槽的本质就是函数,是函数就可以重载,因此,我们可以重载同名的信号,和重载同名的槽函数。

仍然以 CommanderSoldier 为例:

commander.h 中添加重载的 go 信号:

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

signals:
    void go();
    void go(QString);
};

soldier.h 中添加重载的fight槽函数:

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

signals:

public slots:
    void fight();
    void fight(QString);
};

soldier.cpp 中实现重载的fight槽函数:

void Soldier::fight(QString s)
{
    qDebug() << "fight for" << s;
}

接下来在mainwindow.cpp中同时发送重载的两个go信号:

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

    // 1. 创建两个类的实例
    Commander commander;
    Soldier soldier;

    // 2. 建立信号和槽的连接
    connect(&commander, SIGNAL(go()), &soldier, SLOT(fight()));
    connect(&commander, SIGNAL(go(QString)), &soldier, SLOT(fight(QString)));

    // 3. 发送信号
    commander.go();
    commander.go("freedom");
}

此时执行程序,就可以在【应用程序输出】窗口看到两个重载的槽函数执行的结果了:
执行结果


2. 信号槽总结


2.1 使用信号和槽的条件

如果要使用信号和槽,需要满足如下两个条件

  • 自定义的类,要继承自 QObject
  • 自定义的类,其中要声明一个宏 Q_OBJECT

只有满足了这两个条件才可以正常使用信号槽机制。


2.2 信号

  • 无需实现
    信号的本质是函数,并且只需要声明,不需要实现;
  • 可以重载
    信号本质是函数,因此可以重载;
  • 信号声明在类头文件的 signals 域下;
  • 信号返回值类型为 void,参数的类型和个数不限;
  • 信号可以使用 emit 关键字发射,emit 也可以省略;

2.3 槽

  • 需要实现
    槽的本质是函数,需要实现;
  • 可以重载
    槽本质是函数,因此可以重载;
  • 槽函数用 slots 关键字修饰(其实在 Qt5 中可以省略 slots 关键字,下一节会讲解);
  • 返回值
    槽函数的返回值,要和信号保持一致。由于信号的返回值为 void,因此槽函数的返回值也是 void
  • 参数
    槽函数的参数个数要 <= 信号的参数个数
    也就是说:可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少),但是不能说信号根本没有这个数据,你就要在槽函数中使用(就是槽函数的参数比信号的多,这是不允许的)

本节对应的视频讲解:B_站_链_接
https://www.bilibili.com/video/BV1gA4y1d7gz


  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大轮明王讲QT

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值