近段时间,在网上无意间发现一个网友写的关于事件发布与订阅库。
这个框架,名叫QuickEvent,git地址:
https://gitee.com/fmldd/Quick-Event
大家知道关于Qt如何自定义事件,如果不清楚请参考《Qt中的事件(3)- 自定义事件》。
QuickEvent就是基于此基本原理实现的。代码量比较少,只有几百行。目前只能说勉强能用吧,也存在一些问题。当然你也可以基于这个代码,造自己的轮子。开一篇博客,记录下使用,待到要实际使用时,拎过来用就ok。
何为发布、订阅,我们可以类比为向报社订阅报纸,只要有新的报纸印刷,那么你就会收到一份报纸。在程序中,好比有个小本子,只要你订阅了某个事件,就在这个小本子上记录下来,那么当事件来临时,就从小本子上的登记人员依次推送。可能比喻不佳,自行百度吧。
我们先来看QuickApplication类中这2个发布与订阅函数。
static bool subscibeEvent(QObject *listener, QByteArray eventName);
static void publishEvent(QByteArray eventName, Qt::ConnectionType type, Args &&... args)
subscibeEvent参数含义:
publishEvent参数含义:
上例子吧,说了半天都不知道怎么用?
涉及2个窗口类MainWindow、ChildDialog,代码如下:
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();
}
void ChildDialog::on_pushButton_clicked()
{
auto time = QDateTime::currentDateTime();
QuickApplication::publishEvent("show_time", Qt::AutoConnection, time);
}
完成上述2个步骤后,那么你点击ChildDialog中按钮,MainWindow::event_show_time函数就会被调用。这就是发布与订阅。
效果如下:
注:
订阅事件与发布事件,允许多对一,即发布一个事件,允许添加多个订阅者,对同一个事件进行响应处理。
我们定义Student,自定义类型,如下:
Student.h
#include
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
#include "student.h"
#include
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;
}
然后,就像第二节中,进行测试,代码如下:
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_;
}
void ChildDialog::on_pushButton_2_clicked()
{
Student student;
student.name_ = "xiaodong";
student.id_ = "123";
QuickApplication::publishEvent("student_event", Qt::AutoConnection, student);
}
运行效果:
注:
可变长参数就自己去试试吧,这个就不试了。
发布与订阅函数也是线程安全的。
static bool subscibeEvent(QObject *listener, QByteArray eventName);
static void publishEvent(QByteArray eventName, Qt::ConnectionType type, Args &&... args)
发布与订阅事件允许在不同的线程中,比如发布在主线程,订阅在次线程。
其调用订阅者槽函数时,所使用的线程,与Qt::ConnectionType参数有关。与多线程情况下,采用信号槽机制调用槽函数时一致。
这部分内容跟发布与订阅没有太大关系。
QuickEvent中有个类QuickWork,用户派生子类可以指定子类跑在哪个线程上。也算是多线程的一种实现方式。
不过这个我没有仔细研究,可能会有一些问题,目前我只是发现程序退出时,有异常,不知道什么情况,所以就不说了。想了解就自己去看example吧。
若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!
同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。
本文涉及工程代码,公众号回复:48QuickEvent,即可下载。