CTK插件框架学习-信号槽(05)

CTK插件框架学习-事件监听(04)icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/137171155

一、主要流程

  • 信号发送者告诉服务要发送的信号
  • 信号发送者发送信号
  • 信号接收者告诉服务当触发某个订阅的主题时通知槽函数
  • 信号接收者处理槽函数
  • 信号槽参数类型必须为(const ctkEvent&)

二、发布订阅插件

 

2.1、信号发送插件

 

发送信号类

================================SendSignal.h============================
#pragma once

#include <qobject.h>
#include <qstring.h>
#include <service/event/ctkEventAdmin.h>

typedef struct
{
	QString _name;
	QString _message;
}ST_Msg;

class ctkPluginContext;
class SendSignal
	: public QObject
{
	Q_OBJECT

public:
	SendSignal(ctkPluginContext* context);

	void publishMessage(const ST_Msg & msg);

signals:
	void sigSendMessage(const ctkDictionary& dic);

private:
	ctkPluginContext* m_context;
};

================================SendSignal.cpp==============================

#include "SendSignal.h"
#include <qdebug.h>

#include "service/event/ctkEventAdmin.h"
#include "ctkPluginContext.h"

SendSignal::SendSignal(ctkPluginContext * context)
	:m_context(context)
{
	ctkServiceReference ref = context->getServiceReference<ctkEventAdmin>();
	if (ref)
	{
		ctkEventAdmin* eventAdmin = context->getService<ctkEventAdmin>(ref);
		if (eventAdmin)
		{
			eventAdmin->publishSignal(this, SIGNAL(sigSendMessage(const ctkDictionary&)), "SIGNAL_MESSAGE", Qt::DirectConnection);
		}
	}
}

void SendSignal::publishMessage(const ST_Msg & msg)
{
	ctkDictionary dic;
	dic["name"] = msg._name;
	dic["message"] = msg._message;
	ctkEvent event("SIGNAL_MESSAGE", dic);

	qDebug() << "SendSignal message:" << dic;

	emit sigSendMessage(dic);

}

触发器类

=========================PluginActivator.h=================================
#pragma once
#include <qobject.h>
#include "ctkPluginActivator.h"
#include "ctkPluginContext.h"

#include "SendSignal.h"

class PluginActivator :
	public QObject, ctkPluginActivator
{
	Q_OBJECT
	Q_INTERFACES(ctkPluginActivator)//向Qt的插件框架声明,希望将xxx插件放入到框架中。
	Q_PLUGIN_METADATA(IID "TestSignalPlugin")//向qt框架申明插件(qt5版本)


public:
	PluginActivator();
	virtual void start(ctkPluginContext* context);
	virtual void stop(ctkPluginContext* context);

private:
	QScopedPointer<SendSignal> m_sendSignal;//智能指针,自动析构回收
};

=========================PluginActivator.cpp===============================

#include "PluginActivator.h"
#include <qdebug.h>

#include "ctkPluginFrameworkLauncher.h"

PluginActivator::PluginActivator()
{
}


void PluginActivator::start(ctkPluginContext* context)
{
	qDebug() << "my TestSignalPlugin start";
	m_sendSignal.reset(new SendSignal(context));

	ST_Msg msg;
	msg._name = "SendSignal";
	msg._message = "hello Signal send message";
	m_sendSignal->publishMessage(msg);

	ctkPlugin::State sta = context->getPlugin()->getState();
}

void PluginActivator::stop(ctkPluginContext* context)
{
	qDebug() << "my TestSignalPlugin stop";
	Q_UNUSED(context)// Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用


	m_sendSignal.reset(NULL);

	ctkPlugin::State sta = context->getPlugin()->getState();
}

2.2、信号接收插件

 

接收信号类

===========================ReceiveSlot.h===============================
#pragma once

#include <qobject.h>
#include <qstring.h>
#include <service/event/ctkEventAdmin.h>

class ctkPluginContext;
class ReceiveSlot
	: public QObject
{
	Q_OBJECT

public:
	ReceiveSlot(ctkPluginContext* context);

public slots:
	void slotReceiveMessage(const ctkEvent& event);

private:
	ctkPluginContext* m_context;
};

===========================ReceiveSlot.cpp=============================

#include "ReceiveSlot.h"
#include <qdebug.h>

#include "service/event/ctkEventAdmin.h"
#include "ctkPluginContext.h"

ReceiveSlot::ReceiveSlot(ctkPluginContext * context)
	:m_context(context)
{

}

void ReceiveSlot::slotReceiveMessage(const ctkEvent & event)
{
	QString name = event.getProperty("name").toString();
	QString message = event.getProperty("message").toString();

	qDebug() << "ReceiveSlot name:" << name;
	qDebug() << "ReceiveSlot message:" << message;
}

触发器类

============================PluginActivator.h===============================
#pragma once
#include <qobject.h>
#include "ctkPluginActivator.h"
#include "ctkPluginContext.h"

#include "ReceiveSlot.h"

class PluginActivator :
	public QObject, ctkPluginActivator
{
	Q_OBJECT
	Q_INTERFACES(ctkPluginActivator)//向Qt的插件框架声明,希望将xxx插件放入到框架中。
	Q_PLUGIN_METADATA(IID "TestSignalPlugin")//向qt框架申明插件(qt5版本)


public:
	PluginActivator();
	virtual void start(ctkPluginContext* context);
	virtual void stop(ctkPluginContext* context);

private:
	QScopedPointer<ReceiveSlot> m_receiveSlot;//智能指针,自动析构回收
};

============================PluginActivator.cpp===============================

#include "PluginActivator.h"
#include <qdebug.h>

#include "ctkPluginFrameworkLauncher.h"

#include <service/event/ctkEventConstants.h>
#include <service/event/ctkEventAdmin.h>

PluginActivator::PluginActivator()
{
}


void PluginActivator::start(ctkPluginContext* context)
{
	qDebug() << "my TestSlotPlugin start";
	m_receiveSlot.reset(new ReceiveSlot(context));

	ctkDictionary dic;
	dic[ctkEventConstants::EVENT_TOPIC] = "SIGNAL_MESSAGE";//订阅主题
	ctkServiceReference ref = context->getServiceReference<ctkEventAdmin>();
	if (ref)
	{
		ctkEventAdmin* eventAdmin = context->getService<ctkEventAdmin>(ref);
		if (eventAdmin)
		{
			eventAdmin->subscribeSlot(m_receiveSlot.get(), SLOT(slotReceiveMessage(const ctkEvent&)), dic, Qt::DirectConnection);
		}
	}

	ctkPlugin::State sta = context->getPlugin()->getState();
}

void PluginActivator::stop(ctkPluginContext* context)
{
	qDebug() << "my TestSlotPlugin stop";
	Q_UNUSED(context)// Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用


	m_receiveSlot.reset(NULL);

	ctkPlugin::State sta = context->getPlugin()->getState();
}

2.3、测试插件

#include "CTKPlugin.h"
#include <QtWidgets/QApplication>


#include <iostream>
#include <QStyleFactory>
#include <QDir>
#include <QDirIterator>
#include <QDebug>
#include "ctkPluginFrameworkFactory.h"
#include "ctkPluginFramework.h"
#include "ctkPluginException.h"
#include "ctkPluginContext.h"
#include "ctkPluginFrameworkLauncher.h"
#include "../TestPlugin/iTestPlugin.h"
#include "../TestPlugin2/IService1.h"
#include "../TestPlugin2/IService2.h"
#include "../TestPlugin3/IService.h"
/*
* 1、注意:Plugin-SymbolicName要满足这里的前缀是:TARGET/META-INF格式。TARGET的名字最好和工程名一致,不然可能出现device not open错误。
* 2、如果CTK初始化、插件安装启动等是在一个类中,则与CTK相关的变量应定义成类的属性,不能是成员变量,否则获取不到服务
* 3、CTK插件组成:
(1)每个插件有自己的注册器Activator,继承自QObject和ctkPluginActivator的一个类,并实现ctkPluginActivator的start、stop函数
(2)每个插件必须有一个资源文件,名称一般与插件名称一致,前缀必须为TARGET/META-INF,例:插件名称/META-INF
(3)每个插件必须添加一个元数据文件,名字必须为MANIFEST.MF,并添加到资源文件中
* 4、QSharedPointer framework这个对象既可以作为对象也可以作为对象指针,但要作为插件框架使用必须要用指针方法调用
* 5、生成的插件名(TARGET)不要有下划线,因为CTK会默认将插件名中的下划线替换成点号,最后导致找不到插件 
*/
int main(int argc, char *argv[])
{
	QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication a(argc, argv);
	a.setApplicationName("ctktest");//Linux下没有名称报错

	QString path = QCoreApplication::applicationDirPath();

#ifdef _DEBUG
	ctkPluginFrameworkLauncher::addSearchPath(path + "/CTKPlugins");
#else
	ctkPluginFrameworkLauncher::addSearchPath(path + "/CTKPlugins");
#endif // _DEBUG
	// 设置并启动 CTK 插件框架
	try {
		ctkPluginFrameworkLauncher::start("org.commontk.eventadmin");
	}
	catch (ctkException e)
	{
		std::cout << e.message().toStdString() << std::endl;
	}

	// 启动插件工厂
	ctkPluginFrameworkFactory* ctkFrameWorkFactory = new ctkPluginFrameworkFactory;
	QSharedPointer<ctkPluginFramework> framework = ctkFrameWorkFactory->getFramework();
	try {
		framework->init();
		framework->start();
	}
	catch (const ctkPluginException& e)
	{
		std::cout << "framework init fail" << std::endl;
	}

	QSharedPointer<ctkPlugin> plugin;

/*
* 使用MANIFEST.MF启动依赖插件方法未成功,采用独立加载插件方法
*/
#if 0
	QDirIterator iter(path + "/plugins/", { "*.dll" }, QDir::NoFilter, QDirIterator::Subdirectories);
	while (iter.hasNext()) {
		//qDebug() << iter.next();
		QString dllPath = iter.next();
		QUrl url = QUrl::fromLocalFile(dllPath);
		try
		{
			plugin = framework->getPluginContext()->installPlugin(url);
			qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
			
			//获取MANIFEST.MF中的数据
			QHash<QString, QString> headers = plugin->getHeaders();
			ctkVersion version = ctkVersion::parseVersion(headers.value(ctkPluginConstants::PLUGIN_VERSION));
			QString name = headers.value(ctkPluginConstants::PLUGIN_NAME);
		}
		catch (ctkPluginException e) {
			std::cout << e.message().toStdString() << e.getType() << std::endl;
		}

		try {
			plugin->start(ctkPlugin::START_TRANSIENT);//表示立即启用插件,不设置参数的话加载后也不会立即打印输出
			qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
		}
		catch (ctkPluginException e) {
			std::cout << e.message().toStdString() << e.getType() << std::endl;
		}
	}

#else
	
	try
	{
		QUrl url = QUrl::fromLocalFile(path + "/plugins/TestSlotPlugin.dll");
		plugin = framework->getPluginContext()->installPlugin(url);
		qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());

		//获取MANIFEST.MF中的数据
		QHash<QString, QString> headers = plugin->getHeaders();
		ctkVersion version = ctkVersion::parseVersion(headers.value(ctkPluginConstants::PLUGIN_VERSION));
		QString name = headers.value(ctkPluginConstants::PLUGIN_NAME);
	}
	catch (ctkPluginException e) {
		std::cout << e.message().toStdString() << e.getType() << std::endl;
	}

	try {
		plugin->start(ctkPlugin::START_TRANSIENT);//表示立即启用插件,不设置参数的话加载后也不会立即打印输出
		qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
	}
	catch (ctkPluginException e) {
		std::cout << e.message().toStdString() << e.getType() << std::endl;
	}

	try
	{
		QUrl url = QUrl::fromLocalFile(path + "/plugins/TestSignalPlugin.dll");
		plugin = framework->getPluginContext()->installPlugin(url);
		qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());

		//获取MANIFEST.MF中的数据
		QHash<QString, QString> headers = plugin->getHeaders();
		ctkVersion version = ctkVersion::parseVersion(headers.value(ctkPluginConstants::PLUGIN_VERSION));
		QString name = headers.value(ctkPluginConstants::PLUGIN_NAME);
	}
	catch (ctkPluginException e) {
		std::cout << e.message().toStdString() << e.getType() << std::endl;
	}

	try {
		plugin->start(ctkPlugin::START_TRANSIENT);//表示立即启用插件,不设置参数的话加载后也不会立即打印输出
		qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
	}
	catch (ctkPluginException e) {
		std::cout << e.message().toStdString() << e.getType() << std::endl;
	}
#endif

	//ctkPlugin::State sta = plugin->getState();
	//ctkPluginFrameworkLauncher::stop();
	//plugin->stop(); 
	//plugin->uninstall();
	//sta = plugin->getState();

	CTKPlugin c;
	c.show();
    return a.exec();
}

三、类通信和信号槽区别

1、使用event发送效率优于信号槽,信号槽方式会在qt信号槽机制中转再发送到ctk框架

2、两种方式可以混合使用

3、同步:sendEvent / Qt::DirectConnection

4、异步:postEvent / Qt::QueuedConnection

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/512784.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法训练day57leetcode1143.最长公共子序列 1035.不相交的线 53最大子序和

part14 1143.最长公共子序列 1035.不相交的线 53最大子序和 动态规划 1143. 最长公共子序列 初始化动态规划数组 dp 动态规划数组 dp 是一个二维数组&#xff0c;其大小为 (text1.size() 1) x (text2.size() 1)&#xff0c;dp[i][j] 表示 text1 的前 i 个字符和 text2 的前…

对【AI技术创业】有哪些机会进行分析和引导

文章目录 方向一&#xff1a;行业解决方案,以下是一些常见的行业解决方案&#xff1a;方向二&#xff1a;智能产品和服务,以下是一些智能产品和服务的示例&#xff1a;方向三&#xff1a;教育和培训 1.智能客户服务&#xff1a; 利用自然语言处理&#xff08;NLP&#xff09;和…

通过SSH在苹果手机上查看系统文件:远程访问iOS文件系统的方法

​ 目录 引言 用户登录工具和连接设备 查看设备信息&#xff0c;电池信息 查看硬盘信息 硬件信息 查看 基带信息 销售信息 电脑可对手机应用程序批量操作 运行APP和查看APP日志 IPA包安装测试 注意事项 引言 苹果手机与安卓手机不同&#xff0c;无法直接访问系统文件…

【蓝牙协议栈】【BLE】【ATT】低功耗蓝牙之属性协议介绍

1. 精讲蓝牙协议栈&#xff08;Bluetooth Stack&#xff09;&#xff1a;SPP/A2DP/AVRCP/HFP/PBAP/IAP2/HID/MAP/OPP/PAN/GATTC/GATTS/HOGP等协议理论 2. 欢迎大家关注和订阅&#xff0c;【蓝牙协议栈】和【Android Bluetooth Stack】专栏会持续更新中.....敬请期待&#xff01…

zabbix 7.0 新增功能亮点(一)——T参数

概要&#xff1a; T参数是zabbix7.0新增的一项功能&#xff0c;它支持对配置文件进行可用性验证&#xff0c;即zabbix程序(server/proxy/agent等)修改配置文件后&#xff0c;支持-T或–test-config参数验证配置参数可用性。 T参数主要包含以下三个方面的应用场景&#xff1a; …

宁盾身份域管与Coremail邮件系统完成兼容互认证,持续深化信创布局

在信创国产化改造的背景下&#xff0c;企业邮箱的替换是许多党政、央国企、金融、制造企业面临的重要任务。为了满足企业对国产邮箱、OA等其他应用、终端实现统一身份认证&#xff0c;宁盾国产化身份域管与 Coremail XT 安全增强电子邮件系统 V5.0、V6.0 完成了产品兼容互认证&…

新能源汽车充电桩主板产业链解析

新能源汽车充电桩主控制板&#xff0c;简称汽车充电桩主板&#xff0c;是充电桩设施的核心部件&#xff0c;主要负责控制充电桩的整体运行和管理充电过程。了解汽车充电桩主板的整体产业链是非常重要的&#xff0c;这可以帮助您更好地了解供应链、采购渠道以及行业发展趋势。 产…

详细盘点Vue3项目中的各种组件文件夹(用于存放‘.vue’文件)

components 文件夹 存放通用的、可复用的组件&#xff1b; 通常用于构建页面中的具体功能模块。在项目中多次使用&#xff0c;并且不依赖于具体的业务逻辑。 比如&#xff1a;导航栏组件 navbar.vue layouts 文件夹 存放页面的整体布局组件 default.vue <script setup…

从零开始:如何进入IT行业

微信扫码体验我自己做的小程序&#xff08;很有意思哦&#xff5e;&#xff5e;【坏笑】&#xff09;&#xff1a; 随着科技的飞速发展&#xff0c;IT行业已经成为了许多人梦寐以求的职业之一。不过&#xff0c;对于那些没有任何相关经验或技能的人来说&#xff0c;进入这个领域…

WEB安全测试通常要考虑的测试点

1、问题&#xff1a;没有被验证的输入 测试方法&#xff1a; 数据类型&#xff08;字符串&#xff0c;整型&#xff0c;实数&#xff0c;等&#xff09; 允许的字符集 最小和最大的长度 是否允许空输入 参数是否是必须的 重复是否允许 数值范围 特定的值&#xff08;枚举型&a…

Ray Tracking 辐射度量学、渲染方程、全局光照

Basic radiometry (辐射度量学) Radiant flux Radiant energy Definition: Radiant energy is the energy of lectromagnetic radiation. It is measured in units of joules, and denoted by the symbol: \[Q [J Joule] \] Radiant flux (power) Definition: Radiant flux (p…

(模型蒸馏)MCC-KD: Multi-CoT Consistent Knowledge Distillation

论文链接&#xff1a;[2310.14747] MCC-KD: Multi-CoT Consistent Knowledge Distillation (arxiv.org) 背景 近年来&#xff0c;大型语言模型&#xff08;LLMs&#xff09;如GPT-3、BERT等在自然语言处理&#xff08;NLP&#xff09;领域取得了显著的进展。这些模型通过大规…

Windows搭建Lychee图片管理系统结合内网穿透实现公网访问本地图床

文章目录 1.前言2. Lychee网站搭建2.1. Lychee下载和安装2.2 Lychee网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 图床作为图片集中存放的服务网站&#xff0c;可以看做是云存储的一部分&#xff0c;既可…

c++的学习之路:9、STL简介与string(1)

一、STL 1、什么是STL STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且是一个包罗数据结构与算法的软件框架。 也就是说STL就是一个模板&#xff0c;这个模板就是整合了很多库让我们方…

166.乐理基础-五声性调式、宫商角徵羽

如果到这五线谱还没记住还不认识的话去看102.五线谱-高音谱号与103.五线谱-低音谱号这两个里&#xff0c;这里面有五线谱对应的音名&#xff0c;对比着看 如果不认识调号去看112.五线谱的调号&#xff08;一&#xff09;、113.五线谱的调号&#xff08;二&#xff09;、114.快…

java学习之路-类和对象

前言 本文内容&#xff1a; 类的定义及其使用 this的引用 对象的构造及初始化 封装 static成员 代码块讲解 内部类 文章目录 1.类定义和使用 1.1了解什么是面向对象 1.2简单认识类 1.3定义类 1.4栗子 2.类的使用-类的实例化 2.1什么是实例化 2.2类和对象的说明 3.this引…

力扣热门算法题 174. 地下城游戏,189. 轮转数组,198. 打家劫舍

174. 地下城游戏&#xff0c;189. 轮转数组&#xff0c;198. 打家劫舍&#xff0c;每题做详细思路梳理&#xff0c;配套Python&Java双语代码&#xff0c; 2024.03.31 可通过leetcode所有测试用例。 目录 174. 地下城游戏 解题思路 完整代码 Python Java 189. 轮转数…

Python中输出显示台的设置

效果: 前言 这种文字显示的方式很适合新手来学习,毕竟新手还学不到pygame做游戏的, Python入门我们一般都学的是输入输出的游戏,但是如果加上一些文字和背景的改善可能会更好. 如何改变字体颜色 字体颜色(跟他的变量名是一样的): #改变字体颜色 RED \033[91m GREEN \033…

kettle介绍-Step之加密及解密

加密 进入kettle的安装目录 cd /d D:\Application\pdi-ce-6.0.0.0-353\data-integration windows系统命令行执行&#xff1a;Encr.bat -kettle 123 cd /data/data-integration linux/mac系统命令行执行&#xff1a;encr.sh -kettle 123 可生成Encrypted 2be98afc86aa7f2e4cb79…

zabbix绑定钉钉进行通知,网页端添加JavaScript,无脑式操作

文章目录 前言一、编辑zabbix告警JavaScript脚本二、代码如下:编辑消息模板,自定义markdown格式的消息。总结前言 随着人工智能的不断发展,zabbix监控这门技术也越来越重要,一下进入正题。 一、编辑zabbix告警JavaScript脚本 没有没接可以新增媒介 其中URL是你的机器人地…