文章目录
- 一、前言
- 二、工程搭建
- 2.1、新建Qt工程
- 2.2、CTK环境配置
- 三、CTK Plugin Framework使用
- 3.1、主函数启动插件框架
- 3.2、插件的创建
- 3.3、插件的使用
一、前言
CTK保姆级编译教程:https://blog.csdn.net/Mr_robot_strange/article/details/128547331?spm=1001.2014.3001.5501
二、工程搭建
2.1、新建Qt工程
Qt 新建【子目录项目】,项目命名为为CTK_PluginFramework
然后继续新建子项目【Application】,作为主项目,项目结构如下图所示:
2.2、CTK环境配置
1、将CTK编译生成的CTK文件夹复制到工程目录下,例如:
2、将源码文件夹下的 CTK-master/Libs/PluginFramework
文件夹复制到刚刚复制的CTK文件夹下,例如:
3、在CTK文件夹下新建CTK_dependency.pri
,并添加如下内容:
# CTK 安装路径
CTK_INSTALL_PATH = $$PWD/../CTK
# CTK 相关库所在路径(例如:CTKCore.CTKPluginFramework.lib)
CTK_LIB_PATH = $$CTK_INSTALL_PATH/lib/ctk-0.1
# CTK 相关头文件所在路径(例如:ctkPluginFramework.h)
CTK_INCLUDE_PATH = $$CTK_INSTALL_PATH/include/ctk-0.1
# CTK 插件相关头文件所在路径(主要因为用掉了service相关东西)
CTK_INCLUDE_FRAMEWORK_PATH = $$PWD/PluginFramework
# 相关库文件(CTKCore.lib、CTKWidgets.lib)
LIBS += -L$$CTK_LIB_PATH -lCTKCore -lCTKPluginFramework
INCLUDEPATH += $$CTK_INCLUDE_PATH \
$$CTK_INCLUDE_FRAMEWORK_PATH
4、在Application.pro
中导入CTK_dependency.pri
三、CTK Plugin Framework使用
3.1、主函数启动插件框架
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include "ctkPluginFrameworkFactory.h"
#include "ctkPluginFramework.h"
#include "ctkPluginException.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setApplicationName("CTK_PluginFramework");//给框架创建名称,Linux下没有会报错
ctkPluginFrameworkFactory frameWorkFactory;
QSharedPointer<ctkPluginFramework> framework = frameWorkFactory.getFramework();
try {
// 初始化并启动插件框架
framework->init();
framework->start();
qDebug() << "CTK Plugin Framework start ...";
} catch (const ctkPluginException &e) {
qDebug() << "Failed to initialize the plugin framework: " << e.what();
qDebug() << e.message() << e.getType();
}
MainWindow w;
w.show();
return a.exec();
}
QSharedPointer<ctkPluginFramework> framework
:这个对象既可以作为对象,也可以作为对象指针,但要作为插件框架使用必须要用指针方法调用,所以代码里用“->”
注意:如果吧CTK初始化、插件安装启动、获取等操作封装成一个类,则需要把CTK相关的变量定义成类属性,不能是局部变量,否则会出现各种问题,例如获取不了服务、服务引用为空等;
3.2、插件的创建
CTK框架由一个一个可分离的插件组成,框架对插件识别有一定要求;
- ctk插件都有自己的注册器Activator,继承自QObject和ctkPluginActivator的一个类,并实现ctkPluginActivator的start、stop函数;
- ctk插件必须有一个资源文件(名字无所谓),前缀必须是【TARGET/META-INF】,即插【插件名/META_INF】;
- ctk插件有一个元数据文件,名字固定为【MANIFEST.MF】,需要将其导入资源文件【TARGET/META-INF】中;
1、创建插件子项目,命名为【HelloCTK】
2、HelloCTK.pro中添加如下内容
QT += core
QT -= gui
TEMPLATE = lib
CONFIG += plugin
TARGET = HelloCTK
DESTDIR = $$OUT_PWD/bin/plugins
include($$PWD/../CTK/CTK_dependency.pri)
注意:生成的插件名(TARGET)不要有下划线,因为CTK会默认将插件名中的下划线替换为点号,最后就导致找不到插件
3、新建C++类HelloActivator(注册器)
修改HelloActivator代码如下:
#ifndef HELLOACTIVATOR_H
#define HELLOACTIVATOR_H
#include <QObject>
#include "ctkPluginActivator.h"
class HelloActivator : public QObject, public ctkPluginActivator
{
Q_OBJECT
Q_INTERFACES(ctkPluginActivator)
Q_PLUGIN_METADATA(IID "HELLO_CTK")
//向Qt的插件框架声明,希望将xxx插件放入到框架中。
public:
void start(ctkPluginContext* context);
void stop(ctkPluginContext* context);
};
#endif // HELLOACTIVATOR_H
#include "hello_activator.h"
#include <QDebug>
void HelloActivator::start(ctkPluginContext* context)
{
qDebug() << "HelloCTK start";
}
void HelloActivator::stop(ctkPluginContext* context)
{
qDebug() << "HelloCTK stop";
Q_UNUSED(context)
//Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用
}
4、新建资源文件qrc
注意:Plugin-SymbolicName要满足这里的前缀是:TARGET/META-INF格式。TARGET的名字最好和工程名一致,不然可能出现device not open错误。
在HelloCTK文件夹中新建MANIFEST.MF
文件,并加入如下内容:
插件加载后会寻找【同名前缀/META-INF】,所以前缀格式固定,可直接在MF文件里添加自己特有的元数据
Plugin-SymbolicName:HelloCTK
Plugin-Version:1.0.0
Plugin-Number:100 #元数据
将MANIFEST.MF
文件加入资源文件中
MANIFEST.MF
文件包含ctk插件的基本信息,只要ctk框架正常识别到文件中Plugin-SymbolicName等信息,则判定它是一个ctk插件,能够正常调用activator中的start、stop函数。
将MANIFEST.MF
拷贝到插件生成路径下:
在HelloCTK.pro中添加代码:
file.path = $$DESTDIR
file.files = MANIFEST.MF
INSTALLS += file
3.3、插件的使用
右键HelloCTK–>【执行qmake】–>【构建“HelloCTK”】
检查生成了HelloCTK.dll
修改main.cpp
#include "mainwindow.h"
#include <QApplication>
#include "ctkPluginFrameworkFactory.h"
#include "ctkPluginFramework.h"
#include "ctkPluginException.h"
#include "ctkPluginContext.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setApplicationName("CTK_PluginFramework");//给框架创建名称,Linux下没有会报错
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 {
// 安装插件
QString HelloCTK_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/HelloCTK/bin/plugins/HelloCTK.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(HelloCTK_dir));
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;
}
MainWindow w;
w.show();
return a.exec();
}
运行,成功调用HelloCTK中start内打印输出,则表明ctk插件接口正常定义并能成功加载。
其中start(ctkPlugin::START_TRANSIENT)表示立即启用插件,不设置参数的话加载后也不会立即打印输出。