目录
1.生成插件
1.1.环境说明
1.2.服务类,纯虚类,提供接口
1.3.实现插件类,实现纯虚函数
1.4.激活插件,加入ctk框架的生命周期中
1.5.添加资源文件
1.6..pro文件
2.使用此插件
3.总结
1.生成插件
1.1.环境说明
编译ctk:Qt5.12.12+MSVC2017_64+Cmake
生成插件:Qt5.12.2+MSVC2017_64+qmake
1.2.服务类,纯虚类,提供接口
PluginAService.h
#ifndef PLUGINASERVICE_H
#define PLUGINASERVICE_H
#include <QtPlugin>
class PluginAService
{
public:
virtual ~PluginAService() {}
virtual void A_Func() = 0;
};
#define PluginAService_iid "org.commontk.service.demos.PluginAService"
Q_DECLARE_INTERFACE(PluginAService, PluginAService_iid)
//此宏将当前这个接口类声明为接口,后面的一长串就是这个接口的唯一标识。
#endif // PLUGINASERVICE_H
1.3.实现插件类,实现纯虚函数
PluginAImpl.h
#ifndef PLUGINAIMPL_H
#define PLUGINAIMPL_H
#include "PluginAService.h"
#include <QObject>
class ctkPluginContext;
class PluginAImpl : public QObject, public PluginAService
{
Q_OBJECT
Q_INTERFACES(PluginAService)
/*
此宏与Q_DECLARE_INTERFACE宏配合使用。
Q_DECLARE_INTERFACE:声明一个接口类
Q_INTERFACES:当一个类继承这个接口类,表明需要实现这个接口类
*/
public:
PluginAImpl(ctkPluginContext* context);
void A_Func() Q_DECL_OVERRIDE;
};
#endif // PLUGINAIMPL_H
PluginAImpl.cpp
#include "PluginAImpl.h"
#include <QtDebug>
PluginAImpl::PluginAImpl(ctkPluginContext* context)
{
}
void PluginAImpl::A_Func()
{
qDebug() << "A_Func()";
}
1.4.激活插件,加入ctk框架的生命周期中
PluginAActivator.h
#ifndef PLUGINAACTIVATOR_H
#define PLUGINAACTIVATOR_H
#include <QObject>
#include "ctkPluginActivator.h"
#include "PluginAService.h"
class PluginAActivator : public QObject, public ctkPluginActivator
{
Q_OBJECT
Q_INTERFACES(ctkPluginActivator)
Q_PLUGIN_METADATA(IID "PLUGINA")
//向Qt的插件框架声明,希望将xxx插件放入到框架中。
public:
void start(ctkPluginContext* context);
void stop(ctkPluginContext* context);
private:
QSharedPointer<PluginAService> m_s;
};
#endif // PLUGINAACTIVATOR_H
PluginAActivator.cpp
#include "PluginAActivator.h"
#include "PluginAImpl.h"
#include <QDebug>
void PluginAActivator::start(ctkPluginContext* context)
{
PluginAImpl* pluginAImpl = new PluginAImpl(context);
context->registerService<PluginAService>(pluginAImpl);
m_s.reset(pluginAImpl);
}
void PluginAActivator::stop(ctkPluginContext* context)
{
Q_UNUSED(context)
//Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用
}
1.5.添加资源文件
资源名随便取,前缀为:PluginA/META_INF,文件名为:MANIFEST.MF
MANIFEST.MF内容:
注意:MANIFEST.MF的路径必须是这样,:/插件名/META-INF/MANIFEST.MF,否则系统找打不到此资源文件,此插件加载就会报异常。
MANIFEST.MF文件中有很多可填内容,在ctkPluginConstants.h中能找到相关宏定义
1.6..pro文件
include($$PWD/../../Plugins/Plugins.pri)
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
TARGET = PluginA
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
HEADERS += \
PluginAActivator.h \
PluginAImpl.h \
PluginAService.h
SOURCES += \
PluginAActivator.cpp \
PluginAImpl.cpp
RESOURCES += \
resource.qrc
2.使用此插件
main.cpp
#include <QCoreApplication>
#include <ctkPluginFrameworkFactory.h>
#include <ctkPluginFramework.h>
#include <ctkPluginException.h>
#include <ctkPluginContext.h>
#include <QtDebug>
#include <QUrl>
#include "PluginAService.h"
QString static firstPlugin_filePath = "D:/openCode/ctkcreator/bin/qmake/debug/plugins/PluginA.dll";
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QApplication a(argc, argv);
//启动框架
QString path = QCoreApplication::applicationDirPath() + "/linkplugins";
ctkPluginFrameworkLauncher::addSearchPath(path, true);
ctkProperties properties;
properties.insert(ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN, ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
ctkPluginFrameworkFactory fwFactory(properties);
QSharedPointer<ctkPluginFramework> framework = fwFactory.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;
}
// 获取服务引用
ctkServiceReference reference = pluginContext->getServiceReference<PluginAService>();
if (reference) {
// 获取指定 ctkServiceReference 引用的服务对象
PluginAService* service = qobject_cast<PluginAService*>(pluginContext->getService(reference));
if (service != Q_NULLPTR) {
// 调用服务
service->A_Func();
}
}
return a.exec();
}
不出意外,在控制台会打印出"A_Func()"。
3.总结
这就是在Qt和CTK中编写和使用插件的基本流程。CTK作为Qt的扩展,主要用于医疗应用开发,但插件的编写和加载机制仍然遵循Qt的标准做法。希望这能帮助你开始编写自己的CTK插件!