platform | Support |
---|---|
Windos VS-2017 | √ |
Linux Gcc6 | √ |
Mac Gcc6 | √ |
1 | 界面与控制逻辑完全分离 |
---|---|
2 | 事件管理 |
3 | 线程管理 |
4 | 控制类装填 |
引入QUICK_EVENT宏让你的自己定义的类具有发布和订阅事件的能力;
QuickWork、QuickScript默认已经引入QUICK_EVENT。
// 使用QUICK_EVENT宏
class Dialog : public QDialog {
Q_OBJECT
QUICK_EVENT(QDialog)
public:
explicit Dialog(QWidget *parent = nullptr);
...
};
// 继承自QuickWork
class UserWork : public QuickWork {
Q_OBJECT
public:
Q_INVOKABLE explicit UserWork(QObject *parent = nullptr);
...
};
QuickApplication提供了subscibeEvent方法用来订阅一个消息。 QUICK_SUBSCIBE宏可以实现便捷订阅。
// 订阅show_time消息
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog) {
ui->setupUi(this);
QuickApplication::subscibeEvent(this, "show_time");
...
}
// QUICK_SUBSCIBE便捷订阅事件
SessionManager::SessionManager(QuickWork *parent) :
QuickWork(parent) {
QUICK_SUBSCIBE("Manager_LoginType")
QUICK_SUBSCIBE("Widget_SessionType")
this->Initial();
}
QUICK_SUBSCIBE定义:
#define QUICK_SUBSCIBE_OBJ(obj,name)\
QuickApplication::subscibeEvent(obj, name);
#define QUICK_SUBSCIBE(name)\
QuickApplication::subscibeEvent(this, name);
#define QUICK_SUBSCIBE_H(name,lev)\
QuickApplication::subscibeEvent(this, name,lev);
#define QUICK_SUBSCIBE_L(name,lev)\
QuickApplication::subscibeEvent(this, name,100+lev);
QuickApplication提供了publishEvent方法用来发布一个消息。 QUICK_PUBLISH1宏可以实现便捷发布事件。
// 发布show_time消息
TestWork::TestWork(QObject *parent) : QuickWork(parent) {
QTimer::singleShot(2000, this, []() {
auto time = QDateTime::currentDateTime();
QuickApplication::publishEvent("show_time", Qt::AutoConnection, time);
});
}
// QUICK_PUBLISH便捷发布消息
void RightControlManager::Slot_WidgetRightControlType(const qint32 &type) {
switch (type) {
case RightControlWidget::Remodel: {
QUICK_PUBLISH1("Manager_RightControlType", qint32(RightControlWidget::Remodel))
break;
}
default:
break;
}
}
publishEvent定义:
template<class ...Args>
static void publishEvent(QByteArray eventName, Qt::ConnectionType type, Args &&... args) {
...
}
QUICK_PUBLISH定义:
#define QUICK_PUBLISH1(name,arg1)\
QuickApplication::publishEvent(name,Qt::AutoConnection, arg1);
#define QUICK_PUBLISH2(name,arg1,arg2)\
QuickApplication::publishEvent(name,Qt::AutoConnection, arg1,arg2);
#define QUICK_PUBLISH3(name,arg1,arg2,arg3)\
QuickApplication::publishEvent(name,Qt::AutoConnection, arg1,arg2,arg3);
#define QUICK_PUBLISH4(name,arg1,arg2,arg3,arg4)\
QuickApplication::publishEvent(name,Qt::AutoConnection, arg1,arg2,arg3,arg4);
#define QUICK_Direct_PUBLISH1(name,arg1)\
QuickApplication::publishEvent(name,Qt::DirectConnection, arg1);
#define QUICK_Direct_PUBLISH2(name,arg1,arg2)\
QuickApplication::publishEvent(name,Qt::DirectConnection, arg1,arg2);
#define QUICK_Direct_PUBLISH3(name,arg1,arg2,arg3)\
QuickApplication::publishEvent(name,Qt::DirectConnection, arg1,arg2,arg3);
#define QUICK_Queued_PUBLISH1(name,arg1)\
QuickApplication::publishEvent(name,Qt::QueuedConnection, arg1);
#define QUICK_Queued_PUBLISH2(name,arg1,arg2)\
QuickApplication::publishEvent(name,Qt::QueuedConnection, arg1,arg2);
#define QUICK_Queued_PUBLISH3(name,arg1,arg2,arg3)\
QuickApplication::publishEvent(name,Qt::QueuedConnection, arg1,arg2,arg3);
#define QUICK_BlockingQueued_PUBLISH1(name,arg1)\
QuickApplication::publishEvent(name,Qt::BlockingQueuedConnection, arg1);
#define QUICK_BlockingQueued_PUBLISH2(name,arg1,arg2)\
QuickApplication::publishEvent(name,Qt::BlockingQueuedConnection, arg1,arg2);
#define QUICK_BlockingQueued_PUBLISH3(name,arg1,arg2,arg3)\
QuickApplication::publishEvent(name,Qt::BlockingQueuedConnection, arg1,arg2,arg3);
引入发布和订阅功能的类通过实现event_ + 消息名称的槽函数即可接受并处理publishEvent推送消息
private slots:
void event_show_time(const QDateTime &time);
...
void Dialog::event_show_time(const QDateTime &time) {
box->setText(time.toString());
box->show();
}
QuickApplication提供了UnsubscribeEvent方法用来取消订阅消息。 QUICK_DESTRUCT宏可以实现便捷取消订阅。
UnsubscribeEvent定义:
bool QuickApplication::UnsubscribeEvent(QObject *listener, QByteArray eventName) {
QWriteLocker loker(&s_lock);
bool result = false;
if(s_quick_event_pool.contains(eventName)) {
QMap<qint32, QObject *> tmplist = s_quick_event_pool[eventName];
tmplist.remove(tmplist.key(listener));
s_quick_event_pool.insert(eventName, tmplist);
result = true;
}
if(s_quick_event_pool_high.contains(eventName)) {
QMap<qint32, QObject *> tmplist = s_quick_event_pool[eventName];
tmplist.remove(tmplist.key(listener));
s_quick_event_pool.insert(eventName, tmplist);
result = true;
}
if(s_quick_event_pool_low.contains(eventName)) {
QMap<qint32, QObject *> tmplist = s_quick_event_pool[eventName];
tmplist.remove(tmplist.key(listener));
s_quick_event_pool.insert(eventName, tmplist);
result = true;
}
return result;
}
bool QuickApplication::UnsubscribeEvent(QObject *listener) {
QWriteLocker loker(&s_lock);
foreach (auto var, s_quick_event_pool.keys()) {
s_quick_event_pool[var].remove(s_quick_event_pool[var].key(listener));
}
foreach (auto var, s_quick_event_pool_low.keys()) {
s_quick_event_pool[var].remove(s_quick_event_pool[var].key(listener));
}
foreach (auto var, s_quick_event_pool_high.keys()) {
s_quick_event_pool[var].remove(s_quick_event_pool[var].key(listener));
}
return true;
}
QUICK_DESTRUCT定义:
#define QUICK_DESTRUCT \
QuickApplication::UnsubscribeEvent(this);\
默认情况下跟Qt的信号槽一样,根据订阅顺序依次接受并处理消息。QuickEvent把订阅者分为三类,高级别、默认、低级别。当发布消息后,所有订阅者按照高级订阅、默认订阅、低级订阅的顺序依次执行。其中高级订阅和低级订阅分别有自己的顺序,默认订阅则无序。
static QMap < QByteArray, QMap<qint32, QObject *> > s_quick_event_pool_high;
static QMap < QByteArray, QMap<qint32, QObject *> > s_quick_event_pool;
static QMap < QByteArray, QMap<qint32, QObject *> > s_quick_event_pool_low;
QuickEvent发布订阅支持四种模式。
请注意,使用QuickEvent时往往不清楚对方详细代码,使用阻塞发布请务必小心,防止死锁!
ConnectionType::AutoConnection,
// 自动模式发布,
// 订阅者者和发布者在同一个线程使用同步调用。
// 订阅者和发布者不在一个线程采用异步调用。
// 调用时按照顺序执行 QuickApplication::methodIndex调用
ConnectionType::DirectConnection, 同步触发模式发布
// 把本线程所有订阅者打包到一个列队依次顺序执行
ConnectionType::QueuedConnection, 异步触发模式发布
// 把每个线程单独打包成列队,每个线程内依次执行 QApplication::postEvent
ConnectionType::BlockingQueuedConnection, 异步等待模式发布
// 把所有线程所有订阅者按照订阅顺序打包,依次调用
// QuickApplication::methodIndex调用
Quick Event代码模型提供两个控制类: QuickWork、QuickScript
继承自QThread的脚本基类,使用方式
初始化:
执行执行:
结束:
注意:
允许被反射,通过QUICK_AUT宏和QuickController,可以实现控制类的自动实例化。 QuickController类用来实现反射,其内部统一自动实例化QuickWork及其子类。QuickWork的线程归属可以通过 move_type来决定被反射后移动大到线程的位置。
MainThread = 0, //反射在主线程中且不移动,start函数不能为死循环否者QT事件循环也将被卡死;
WorkThread, //反射在工作线程中,区别与主线程;
NewThread //反射在新的线程中,会被每个反射出对象创建一个新的线程;
QUICK_AUTO宏作用
QUICK_AUTO定义:
#define QUICK_AUTO(ClassName)\
Q_DECLARE_METATYPE(ClassName *) \
static int ClassId##ClassName = qRegisterMetaType<ClassName *>();\
static void *ThisPtr##ClassName = QuickController::NewInstance(#ClassName);
#define QUICK_AUTO_H(ClassName,value)\
Q_DECLARE_METATYPE(ClassName *) \
static int ClassId##ClassName = qRegisterMetaType<ClassName *>();\
static void *ThisPtr##ClassName = QuickController::NewInstance(\
#ClassName,QuickController::High,value);
#define QUICK_AUTO_L(ClassName,value)\
Q_DECLARE_METATYPE(ClassName *) \
static int ClassId##ClassName = qRegisterMetaType<ClassName *>();\
static void *ThisPtr##ClassName = QuickController::NewInstance(\
#ClassName,QuickController::Low,value);
QuickController反射QuickWork及其子类顺序类似订阅顺序,分为三个级别。高优先级、默认、低优先级。先反射高优先级类、默认优先级类、低优先级类。其中默认优先级里的类无序,高优先级、低优先级里类有序。
原理:C/C++无法在main之前执行复杂的操作,通过在.h文件中定义static变量且通过函数方式赋值,可以main之前执行一段代码,利用static在类外修饰变量表示该变量仅对于文件内部可见的原理,不会产生编译错误;[当然对C++11支持良好编译器可以使用constexpr]但是这个操作可能被执行多次,所以反射类列表使用了Set容器防止重复插入;
----------------- QuickController OrderLow cover:-----------------
cover key: 25
cover name: "TestWork" "UserWork"
----------------------------------
只使用QuickEvent的发布订阅功能无需初始化。QuickEvent的控制类反射与生存周期管理QuickController需要在main函数中初始化。 QUICK_INSTALL() 宏和 QUICK_INSTALL_DETAILED() 宏均可实现初始化,QUICK_INSTALL_DETAILED() 增加了打印 QuickEvent 更详细的相关信息,比如版本信息、详细发布订阅列队等,方便调试使用。
#include "dialog.h"
#include <QuickEvent>
#include <QFile>
int main(int argc, char **argv) {
QApplication a(argc, argv);
QUICK_INSTALL()// QUICK_INSTALL QUICK_INSTALL_DETAILED
QUICK_SETSTYLE("../../Examples/resource/Style/gray_style.qss")
Dialog dialog;
dialog.show();
return a.exec();
}
QuickEvent宏 | 说明 |
---|---|
QUICK_AUTO(ClassName) | 向QT元对象系统注册自己类型、实例化本身(默认优先级) |
QUICK_AUTO_H(ClassName,value) | 向QT元对象系统注册自己类型、实例化本身(高优先级) |
QUICK_AUTO_L(ClassName,value) | 向QT元对象系统注册自己类型、实例化本身(低优先级) |
QUICK_EVENT(PARENTANME) | 使类本身支持发布订阅功能 |
- | - |
QUICK_DESTRUCT | 取消自身的所有订阅 |
- | - |
QUICK_SUBSCIBE_OBJ(obj,name) | 便捷订阅,订阅者、订阅名称(订阅者可以是自己内部变量) |
QUICK_SUBSCIBE(name) | 向自身便捷订阅 |
QUICK_SUBSCIBE_H(name,lev) | 向自身便捷高级订阅,lev表示高级订阅中的排序,重复则顶掉之前 |
QUICK_SUBSCIBE_L(name,lev) | 向自身便捷低级订阅,lev表示低级订阅中的排序,重复则顶掉之前 |
- | - |
QUICK_PUBLISH1(name,arg1) | 默认模式发布,1个参数 |
QUICK_PUBLISH2(name,arg1,arg2) | 默认模式发布,2个参数 |
QUICK_PUBLISH3(name,arg1,arg2,arg3) | 默认模式发布,3个参数 |
QUICK_PUBLISH4(name,arg1,arg2,arg3,arg4) | 默认模式发布,4个参数 |
QUICK_Direct_PUBLISH1(name,arg1) | 同步模式发布,1个参数 |
QUICK_Direct_PUBLISH2(name,arg1,arg2) | 同步模式发布,2个参数 |
QUICK_Direct_PUBLISH3(name,arg1,arg2,arg3) | 同步模式发布,3个参数 |
QUICK_Queued_PUBLISH1(name,arg1) | 异步模式发布,1个参数 |
QUICK_Queued_PUBLISH2(name,arg1,arg2) | 异步模式发布,2个参数 |
QUICK_Queued_PUBLISH3(name,arg1,arg2,arg3) | 异步模式发布,3个参数 |
QUICK_BlockingQueued_PUBLISH1(name,arg1) | 异步等待模式发布,1个参数 |
QUICK_BlockingQueued_PUBLISH2(name,arg1,arg2) | 异步等待模式发布,2个参数 |
QUICK_BlockingQueued_PUBLISH3(name,arg1,arg2,arg3) | 异步等待模式发布,3个参数 |
- | - |
QUICK_GETSET(name,type) | 变量快速读写接口 |
QUICK_INITIAL_VAR(name,type) | 变量快速定义、读写接口 |
QUICK_GETSET_Object(name,type) | 指针快速读写接口 |
- | - |
QUICK_INSTALL() | QuickController初始化 |
QUICK_INSTALL_DETAILED() | QuickController初始化,打印详细信息 |
QUICK_SETSTYLE(name) | 样式表初始化 |
问题在于QT元对象系统对于方法参数类型的摘要(QMetaMethod::parameterTypes)和C++的typeid()差距过大。目前只匹配外部类型,对于模板无法处理,所以不建议重载参数个数相同的事件响应函数。比如:
void event_show_time(const QDateTime &time, QList<int> list);
void event_show_time(const QDateTime &time, QList<QString> list);
#true编译生成动态库; false编译生成静态库;
set(quickevent_BUILD_SHARED_LIBS false)
#ON编译示例 OFF不编译示例
set(quickevent_BUILD_EXAMPLES ON)
static int qt_metatype_id()
{
static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
//继承自dll导出类的对象T模板类型无法识别,需要Q_DECLARE_METATYPE前置声明
const char * const cName = T::staticMetaObject.className();
...
}
----------------- QuickController Initialization:-----------------
Lib Name: "QuickEvent"
Lib VER: "3.0.1"
Controlle QuickWorks: ("High0", "High1", "High2", "Disorder2", "Disorder1", "Disorder0", "Low0", "Low1", "Low2")
----------------------------------
"High0 Initialization complete"
"High1 Initialization complete"
"High2 Initialization complete"
"Disorder2 Initialization complete"
"Disorder1 Initialization complete"
"Disorder0 Initialization complete"
"Low0 Initialization complete"
"Low1 Initialization complete"
"Low2 Initialization complete"
"High0 End of deconstruction"
"High1 End of deconstruction"
"High2 End of deconstruction"
"Disorder2 End of deconstruction"
"Disorder1 End of deconstruction"
"Disorder0 End of deconstruction"
"Low0 End of deconstruction"
"Low1 End of deconstruction"
"Low2 End of deconstruction"
----------------- QuickController Initialization:-----------------
Lib Name: "QuickEvent"
Lib VER: "3.0.1"
Controlle QuickWorks: ("Disorder3", "Disorder2", "Disorder0", "Disorder1")
----------------------------------
Disorder3 Initialization QThread(0x1b9428d5fa0, name = "Main Thread")
Disorder2 Initialization QThread(0x1b9428d5fa0, name = "Main Thread")
Disorder0 Initialization QThread(0x1b9428d5fa0, name = "Main Thread")
Disorder1 Initialization QThread(0x1b9428d5fa0, name = "Main Thread")
Disorder0 Run QThread(0x1b9428d5fa0, name = "Main Thread")
Disorder2 Run QThread(0x1b9428f94c0)
Disorder3 Run msleep Begin QThread(0x1b9428f9400, name = "Work Thread")
Disorder3 Run msleep End QThread(0x1b9428f9400, name = "Work Thread")
Disorder1 Run msleep Begin QThread(0x1b9428f9400, name = "Work Thread")
Disorder1 Run msleep End QThread(0x1b9428f9400, name = "Work Thread")
-------------quit-------------
"Disorder2 End of deconstruction"
"Disorder3 End of deconstruction"
"Disorder1 End of deconstruction"
"Disorder0 End of deconstruction"
WorkThread的start耗时操作会阻塞所有WorkThread中订阅事件
----------------- QuickController Initialization:-----------------
Lib Name: "QuickEvent"
Lib VER: "3.0.1"
Controlle QuickWorks: ("MainThreadSubscibe", "MainThreadPublish", "NewThreadPublish", "WorkThreadPublish", "NewThreadSubscibe", "WorkThreadSubscibe")
----------------------------------
-------------Main Thread Publish-------------
----------------- publishEvent:-----------------
Event name: "Example4"
Event ConnectionType: Qt::AutoConnection
Event Args: Qt::AutoConnection
Event Thread: QThread(0x20815dc6640, name = "Main Thread")
----------------------------------
MainThreadSubscibe QThread(0x20815dc6640, name = "Main Thread")
NewThreadSubscibe QThread(0x20815df18b0)
-------------Work Thread Publish-------------
----------------- publishEvent:-----------------
Event name: "Example4"
Event ConnectionType: Qt::AutoConnection
Event Args: Qt::AutoConnection
Event Thread: QThread(0x20815de8820, name = "Work Thread")
----------------------------------
WorkThreadSubscibe QThread(0x20815de8820, name = "Work Thread")
MainThreadSubscibe QThread(0x20815dc6640, name = "Main Thread")
NewThreadSubscibe QThread(0x20815df18b0)
WorkThreadSubscibe QThread(0x20815de8820, name = "Work Thread")
-------------New Thread Publish-------------
----------------- publishEvent:-----------------
Event name: "Example4"
Event ConnectionType: Qt::AutoConnection
Event Args: Qt::AutoConnection
Event Thread: QThread(0x20815de86c0)
----------------------------------
MainThreadSubscibe QThread(0x20815dc6640, name = "Main Thread")
NewThreadSubscibe QThread(0x20815df18b0)
WorkThreadSubscibe QThread(0x20815de8820, name = "Work Thread")
-------------Quit-------------
----------------- QuickController Initialization:-----------------
Lib Name: "QuickEvent"
Lib VER: "3.0.1"
Controlle QuickWorks: ("NewThreadSubscibe1", "NewThreadSubscibe2")
----------------------------------
----------------- subscibeEvent:-----------------
listener: NewThreadSubscibe1(0x23c34998610)
Event name: "Example5"
subscibe level Disorder
Event Thread "Main Thread"
----------------------------------
----------------- subscibeEvent:-----------------
listener: NewThreadSubscibe2(0x23c34998950)
Event name: "Example5"
subscibe level Disorder
Event Thread "Main Thread"
----------------------------------
-------------Direct PUBLISH-------------
----------------- publishEvent:-----------------
Event name: "Example5"
Event ConnectionType: Qt::DirectConnection
Event Args: Qt::DirectConnection
Event Thread: QThread(0x23c34976690, name = "Main Thread")
----------------------------------
New1 Subscibe bugin QThread(0x23c34998570)
New2 Subscibe bugin QThread(0x23c349988d0)
New2 Subscibe end QThread(0x23c349988d0)
New1 Subscibe end QThread(0x23c34998570)
-------------Queued PUBLISH-------------
----------------- publishEvent:-----------------
Event name: "Example5"
Event ConnectionType: Qt::QueuedConnection
Event Args: Qt::QueuedConnection
Event Thread: QThread(0x23c34976690, name = "Main Thread")
----------------------------------
New1 Subscibe bugin QThread(0x23c34998570)
New2 Subscibe bugin QThread(0x23c349988d0)
New2 Subscibe end QThread(0x23c349988d0)
New1 Subscibe end QThread(0x23c34998570)
-------------Blocking Queued PUBLISH-------------
----------------- publishEvent:-----------------
Event name: "Example5"
Event ConnectionType: Qt::BlockingQueuedConnection
Event Args: Qt::BlockingQueuedConnection
Event Thread: QThread(0x23c34976690, name = "Main Thread")
----------------------------------
New1 Subscibe bugin QThread(0x23c34998570)
New1 Subscibe end QThread(0x23c34998570)
New2 Subscibe bugin QThread(0x23c349988d0)
New2 Subscibe end QThread(0x23c349988d0)
-------------Auto PUBLISH1-------------
----------------- publishEvent:-----------------
Event name: "Example5"
Event ConnectionType: Qt::AutoConnection
Event Args: Qt::AutoConnection
Event Thread: QThread(0x23c34976690, name = "Main Thread")
----------------------------------
New1 Subscibe bugin QThread(0x23c34998570)
New2 Subscibe bugin QThread(0x23c349988d0)
New2 Subscibe end QThread(0x23c349988d0)
New1 Subscibe end QThread(0x23c34998570)
-------------Quit-------------
"NewThreadSubscibe1 End of deconstruction"
"NewThreadSubscibe2 End of deconstruction"
Bruce
Gitee
https://gitee.com/fmldd
个人博客
https://me.csdn.net/dadabruce
Beyond欣
Gitee
https://gitee.com/yaoxin001
个人博客
http://118.25.63.144
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
1. 开源生态
2. 协作、人、软件
3. 评估模型