CTK 框架之多个插件使用同一接口
1、大致流程
2、代码实现
接口函数类:
#ifndef WELCOMESERVICE_H #define WELCOMESERVICE_H /* 多个插件使用同一接口 */ #include <QObject> class WelcomeSerive{ public: virtual ~WelcomeSerive(){} virtual void welcome() = 0; }; Q_DECLARE_INTERFACE(WelcomeSerive, "welcome") #endif // WELCOMESERVICE_H
插件1:
#ifndef SAYQT_H #define SAYQT_H #include <QObject> #include "welcomeservice.h" class ctkPluginContext; class SayQT : public QObject,public WelcomeSerive { Q_OBJECT Q_INTERFACES(WelcomeSerive) public: SayQT(); void welcome(); }; #endif // SAYQT_H
.cpp
#include "sayqt.h" #include "ctkPluginContext.h" #include <QDebug> SayQT::SayQT() { } void SayQT::welcome() { qDebug()<<"Hello QT"; }
插件2
#ifndef SAYWELCOME_H #define SAYWELCOME_H #include <QObject> #include "welcomeservice.h" class ctkPluginContext; class SayWelcome : public QObject, public WelcomeSerive { Q_OBJECT Q_INTERFACES(WelcomeSerive) public: SayWelcome(); void welcome(); }; #endif // SAYWELCOME_H
.cpp
#include "saywelcome.h" #include <QDebug> #include "ctkPluginContext.h" SayWelcome::SayWelcome() { } void SayWelcome::welcome() { qDebug()<<"welcome CTK"; }
注册类
#ifndef SENCONDSERVICE_H #define SENCONDSERVICE_H #include <QObject> #include "ctkPluginContext.h" #include "ctkPluginActivator.h" #include "saywelcome.h" #include "sayqt.h" class sencondService : public QObject,public ctkPluginActivator { Q_OBJECT Q_INTERFACES(ctkPluginActivator) Q_PLUGIN_METADATA(IID "welasdcome") public: sencondService(); void start(ctkPluginContext *context); void stop(ctkPluginContext *context); }; #endif // SENCONDSERVICE_H
.cpp
#include "sencondservice.h" #include "ctkDictionary.h" sencondService::sencondService() { } void sencondService::start(ctkPluginContext *context) { ctkDictionary properties; //插件1 properties.insert(ctkPluginConstants::SERVICE_RANKING, 1); properties.insert("name", "CTK"); SayWelcome *m_pImpl = new SayWelcome(); context->registerService<WelcomeSerive>(m_pImpl, properties); // ctkDictionary properties; // 插件2 properties.insert(ctkPluginConstants::SERVICE_RANKING, 2); properties.insert("name", "QT"); SayQT *pImpl = new SayQT(); context->registerService<WelcomeSerive>(pImpl, properties); } void sencondService::stop(ctkPluginContext *context) { Q_UNUSED(context); }
资源文件:
红色的标记表示的是工程名。
MANIFEST.MF内容
Plugin-SymbolicName:TwoTest Plugin-Version:1.0.0
其中
Plugin-SymbolicName:TwoTest是必须要得,TwoTest这个可随便取。
.pro文件
QT += core QT -= gui TARGET = WelcomeCTK TEMPLATE = lib CONFIG += plugin # ctk源码路径 INCLUDEPATH += C:/Users/ch-pc/Desktop/CTK-master/Libs/Core \ += C:/Users/ch-pc/Desktop/CTK-master/Libs/PluginFramework # ctk安装路径,主要用到的头文件等 INCLUDEPATH += C:/Users/ch-pc/Desktop/CTK-master/build_MSVC2017_64/CTK-build/Libs/PluginFramework INCLUDEPATH += C:/Users/ch-pc/Desktop/CTK-master/build_MSVC2017_64/CTK-build/Libs/Core # ctk动态库路径 LIBS += -LC:/Users/ch-pc/Desktop/CTK-master/build_MSVC2017_64/CTK-build/bin/Debug -lCTKCore -lCTKPluginFramework # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 HEADERS += \ welcomeservice.h \ saywelcome.h \ sencondservice.h \ sayqt.h \ # welcome_ctk.h SOURCES += \ saywelcome.cpp \ sencondservice.cpp \ sayqt.cpp \ # welcome_ctk.cpp RESOURCES += \ pro.qrc
ctk插件的调用
.pro文件
QT -= gui CONFIG += c++11 console CONFIG -= app_bundle INCLUDEPATH += C:/Users/ch-pc/Desktop/CTK-master/Libs/Core \ += C:/Users/ch-pc/Desktop/CTK-master/Libs/PluginFramework \ INCLUDEPATH += C:/Users/ch-pc/Desktop/CTK-master/build_MSVC2017_64/CTK-build/Libs/PluginFramework INCLUDEPATH += C:/Users/ch-pc/Desktop/CTK-master/build_MSVC2017_64/CTK-build/Libs/Core LIBS += -LC:/Users/ch-pc/Desktop/CTK-master/build_MSVC2017_64/CTK-build/bin/Debug -lCTKCore -lCTKPluginFramework # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target
main.cpp文件
#include <QCoreApplication> #include <ctkPluginFrameworkFactory.h> #include <ctkPluginFramework.h> #include <ctkPluginException.h> #include <ctkPluginContext.h> #include <QtDebug> #include <QUrl> #include "welcomeservice.h" QString static firstPlugin_filePath = "D:/program object/WelcomeCTK/debug/WelcomeCTK.dll"; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); ctkPluginFrameworkFactory frameworkFactory; QSharedPointer<ctkPluginFramework> framework = frameworkFactory.getFramework(); // 初始化并启动插件框架 try { framework->init(); framework->start(); qDebug() << "CTK plugin framework start..."; } catch (const ctkPluginException &e) { qDebug() << "CTK plugin framework init err: " << e.what(); return -1; } // 获取插件服务的contex ctkPluginContext* pluginContext = framework->getPluginContext(); try { // 安装插件 QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(firstPlugin_filePath)); qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString()); // 启动插件 plugin->start(ctkPlugin::START_TRANSIENT); qDebug() << "Plugin start..."; } catch (const ctkPluginException &e) { qDebug() << QString("Failed install or run plugin: ") << e.what(); return -2; } // 获取服务引用 QList<ctkServiceReference> refs = pluginContext->getServiceReferences<WelcomeSerive>(); foreach (ctkServiceReference ref, refs) { if (ref) { qDebug() << "Name:" << ref.getProperty("name").toString()<< "Service ranking:" <<ref.getProperty(ctkPluginConstants::SERVICE_RANKING).toLongLong()<< "Service id:" <<ref.getProperty(ctkPluginConstants::SERVICE_ID).toLongLong(); WelcomeSerive* service = qobject_cast<WelcomeSerive *>(pluginContext->getService(ref)); if (service != Q_NULLPTR) service->welcome(); } } qDebug() << "********************"; return a.exec(); }
运行结果:
总结:
在注册两插件时,我开始定义了两个cpp,但是报了一个错误
具体产生的原因好像是在一个动态库只能调用一次Q_PLUGIN_METADATA(IID "welasdcome")这个。所以我删除了一个cpp把它注册插件的内容放在了一个cpp里面。
在进行插件之间通信时,需要主要一般是先调用接收事件的插件,然后在调用发送事件的插件