基于Qt事件发布与订阅框架QuickEvent使用


近段时间,在网上无意间发现一个网友写的关于事件发布与订阅库。

这个框架,名叫QuickEvent,git地址:

https://gitee.com/fmldd/Quick-Event

大家知道关于Qt如何自定义事件,如果不清楚请参考《Qt中的事件(3)- 自定义事件》。

QuickEvent就是基于此基本原理实现的。代码量比较少,只有几百行。目前只能说勉强能用吧,也存在一些问题。当然你也可以基于这个代码,造自己的轮子。开一篇博客,记录下使用,待到要实际使用时,拎过来用就ok。

一、发布与订阅扫盲

何为发布、订阅,我们可以类比为向报社订阅报纸,只要有新的报纸印刷,那么你就会收到一份报纸。在程序中,好比有个小本子,只要你订阅了某个事件,就在这个小本子上记录下来,那么当事件来临时,就从小本子上的登记人员依次推送。可能比喻不佳,自行百度吧。

二、基本使用方法

我们先来看QuickApplication类中这2个发布与订阅函数。

1
2
static bool subscibeEvent(QObject *listener, QByteArray eventName);
static void publishEvent(QByteArray eventName, Qt::ConnectionType type, Args &&... args)

subscibeEvent参数含义:

  • listener表示订阅者
  • eventName表示事件名称

publishEvent参数含义:

  • eventName表示事件名称
  • type 连接类型,这是qt库中的类型。
  • args 可变长参数

上例子吧,说了半天都不知道怎么用?

涉及2个窗口类MainWindow、ChildDialog,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    childDialog = new ChildDialog(this);
    childDialog->show();

    QuickApplication::subscibeEvent(this, "show_time");
}
void MainWindow::event_show_time(const QDateTime &time)
{
    qDebug() << "recv time:" << time.toString();
}
1
2
3
4
5
void ChildDialog::on_pushButton_clicked()
{
    auto time = QDateTime::currentDateTime();
    QuickApplication::publishEvent("show_time", Qt::AutoConnection, time);
}
  • 先使用QuickApplication::subscibeEvent()订阅"show_time"事件,订阅者为MainWindow对象自己,然后添加event_show_time()槽函数用于处理"show_time"事件,槽函数名称必须为event_+“事件名称”。
  • 然后在ChildDialog中按钮槽函数中,使用QuickApplication::publishEvent()发布"show_time"事件,并传递time值。

完成上述2个步骤后,那么你点击ChildDialog中按钮,MainWindow::event_show_time函数就会被调用。这就是发布与订阅。

效果如下:

在这里插入图片描述

注:

订阅事件与发布事件,允许多对一,即发布一个事件,允许添加多个订阅者,对同一个事件进行响应处理。

三、支持自定义类型参数与可变长参数

我们定义Student,自定义类型,如下:

Student.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <QObject>

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

    Student(const Student &other);
    Student &operator=(const Student &other);

public:
    //编号
    QString     id_;
    //名称
    QString     name_;
};

Q_DECLARE_METATYPE(Student)

注:

自定义类型必须使用Q_DECLARE_METATYPE声明,否则Qt无法识别。

Student.cpp

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
#include "student.h"
#include <QDebug>

Student::Student(QObject *parent) : QObject(parent)
{
    qDebug() << "Student:" << this;
}

Student::~Student()
{
    qDebug() << "~Student:" << this;
}

Student::Student(const Student &other)
{
    qDebug() << "Copy Student:" << this;
    this->name_ = other.name_;
    this->id_ = other.id_;
}

Student &Student::operator=(const Student &other)
{
    this->name_ = other.name_;
    this->id_ = other.id_;
    return *this;
}

然后,就像第二节中,进行测试,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    childDialog = new ChildDialog(this);
    childDialog->show();

    QuickApplication::subscibeEvent(this, "student_event");
}

void MainWindow::event_student_event(const Student &stu)
{
    qDebug() << "recv student:" << stu.name_ << stu.id_;
}
1
2
3
4
5
6
7
void ChildDialog::on_pushButton_2_clicked()
{
    Student student;
    student.name_ = "xiaodong";
    student.id_ = "123";
    QuickApplication::publishEvent("student_event", Qt::AutoConnection, student);
}

运行效果:

在这里插入图片描述

注:

可变长参数就自己去试试吧,这个就不试了。

四、线程安全性

发布与订阅函数也是线程安全的。

1
2
static bool subscibeEvent(QObject *listener, QByteArray eventName);
static void publishEvent(QByteArray eventName, Qt::ConnectionType type, Args &&... args)

发布与订阅事件允许在不同的线程中,比如发布在主线程,订阅在次线程。

其调用订阅者槽函数时,所使用的线程,与Qt::ConnectionType参数有关。与多线程情况下,采用信号槽机制调用槽函数时一致。

五、派生QuickWork类实现多线程

这部分内容跟发布与订阅没有太大关系。

QuickEvent中有个类QuickWork,用户派生子类可以指定子类跑在哪个线程上。也算是多线程的一种实现方式。

不过这个我没有仔细研究,可能会有一些问题,目前我只是发现程序退出时,有异常,不知道什么情况,所以就不说了。想了解就自己去看example吧。

在这里插入图片描述

本文工程代码地址:

https://gitee.com/bailiyang/cdemo/tree/master/Qt/48QuickEvent/QuickEvent

===================================================

===================================================

业余时间不定期更新一些想法、思考文章,欢迎关注,共同探讨,沉淀技术!