赞
踩
随着开发的深入,CTK框架还是要关注一下。了解CTK还是有必要的。本篇文章主要描述CTK框架加载带界面的插件,集成到主界面的操作。
什么是CTK? CTK怎么编译?这些就不赘述了,提供几个参考博客即可。
环境:Qt5.15.2 + vs2019(Qt6放弃吧,目前为止编不了;mingw也放弃吧,目前虽然能编过去,但是运行起来就崩溃。当前时间2024.1.11)
编译参考:https://blog.csdn.net/Mr_robot_strange/article/details/128547331
ctk框架使用demo参考:https://github.com/Waleon/CTK-examples
本次demo就是从Waleon的一个模块更改的。
ctk框架核心主要有2点:框架和插件。框架加载插件,之间的通讯使用事件或者信号槽。
框架的核心就是框架和需要调用的服务类(一个纯虚类,同插件共用一个)
QT += core gui widgets
TEMPLATE = app
CONFIG += console
TARGET = App
DESTDIR = $$OUT_PWD/../bin
include($$PWD/../CTK.pri)
SOURCES += \
MainWindow.cpp \
main.cpp
FORMS += \
MainWindow.ui
HEADERS += \
MainWindow.h
# CTK 安装路径
CTK_INSTALL_PATH = $$PWD/../CTKInstall_vs
# CTK 插件相关库所在路径(例如:CTKCore.lib、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/../../../CTK-master/Libs/PluginFramework
LIBS += -L$$CTK_LIB_PATH -lCTKCore -lCTKPluginFramework
INCLUDEPATH += $$CTK_INCLUDE_PATH \
$$CTK_INCLUDE_FRAMEWORK_PATH
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); void addWidget(QList<QWidget*> wigList); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
#include "MainWindow.h" #include "ui_MainWindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::addWidget(QList<QWidget *> wigList) { if (wigList.isEmpty()) { return; } for (auto wig : wigList) { ui->widget->layout()->addWidget(wig); } }
#include <QCoreApplication> #include <QApplication> #include <QDirIterator> #include <QtDebug> #include <ctkPluginFrameworkFactory.h> #include <ctkPluginFramework.h> #include <ctkPluginException.h> #include <ctkPluginContext.h> #include "../Service/welcome_service.h" #include "MainWindow.h" int main(int argc, char *argv[]) { // QCoreApplication app(argc, argv); QApplication app(argc, argv); 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(); return -1; } qDebug() << "********************"; // 获取插件上下文 ctkPluginContext* context = framework->getPluginContext(); // 获取插件所在位置 QString path = QCoreApplication::applicationDirPath() + "/plugins"; // 遍历路径下的所有插件 QDirIterator itPlugin(path, QStringList() << "*.dll" << "*.so", QDir::Files); while (itPlugin.hasNext()) { QString strPlugin = itPlugin.next(); try { // 安装插件 QSharedPointer<ctkPlugin> plugin = context->installPlugin(QUrl::fromLocalFile(strPlugin)); // 启动插件 plugin->start(ctkPlugin::START_TRANSIENT); qDebug() << "Plugin start:" << QFileInfo(strPlugin).fileName(); } catch (const ctkPluginException &e) { qDebug() << "Failed to start plugin" << e.what(); return -1; } } qDebug() << "********************"; // 1. 获取所有服务 QList<ctkServiceReference> refs = context->getServiceReferences<WelcomeService>(); 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(); WelcomeService* service = qobject_cast<WelcomeService *>(context->getService(ref)); if (service != Q_NULLPTR) service->welcome(); } } qDebug() << "********************"; // 2. 使用过滤表达式,获取感兴趣的服务 refs = context->getServiceReferences<WelcomeService>("(&(name=CTK))"); foreach (ctkServiceReference ref, refs) { if (ref) { WelcomeService* service = qobject_cast<WelcomeService *>(context->getService(ref)); if (service != Q_NULLPTR) service->welcome(); } } qDebug() << "********************"; // 3. 获取某一个服务(由 Service Ranking 和 Service ID 决定) ctkServiceReference ref = context->getServiceReference<WelcomeService>(); if (ref) { WelcomeService* service = qobject_cast<WelcomeService *>(context->getService(ref)); if (service != Q_NULLPTR) service->welcome(); } QList<QWidget*> wigList; refs = context->getServiceReferences<WelcomeService>("(&(name=Qui))"); foreach (ctkServiceReference ref, refs) { if (ref) { WelcomeService* service = qobject_cast<WelcomeService *>(context->getService(ref)); if (service != Q_NULLPTR) { wigList << service->widget(); wigList << service->widget(); } } } MainWindow w; w.addWidget(wigList); w.show(); return app.exec(); }
插件的核心就是实现类(实现一个纯虚类,框架只调用纯虚类的方法 )和激活类。就拿WelcomeQui举例吧
QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 plugin TEMPLATE = lib TARGET = WelcomeQui DESTDIR = $$OUT_PWD/../../bin/plugins include($$PWD/../../CTK.pri) # 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 SOURCES += \ MainWindow.cpp \ WelcomeQuiActivator.cpp \ WelcomeQuiImpl.cpp HEADERS += \ MainWindow.h \ WelcomeQuiActivator.h \ WelcomeQuiImpl.h FORMS += \ MainWindow.ui # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target RESOURCES += \ Resource.qrc
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
#include "MainWindow.h"
#include "ui_MainWindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
#ifndef WELCOMEQUIACTIVATOR_H #define WELCOMEQUIACTIVATOR_H #include <QObject> #include <ctkPluginActivator.h> class WelcomeQuiImpl; class WelcomeQuiActivator : public QObject, public ctkPluginActivator { Q_OBJECT Q_INTERFACES(ctkPluginActivator) Q_PLUGIN_METADATA(IID "WELCOME_QUI") public: void start(ctkPluginContext* context); void stop(ctkPluginContext* context); private: WelcomeQuiImpl *m_pImpl; signals: }; #endif // WELCOMEQUIACTIVATOR_H
#include "WelcomeQuiActivator.h" #include "WelcomeQuiImpl.h" #include <QDebug> void WelcomeQuiActivator::start(ctkPluginContext* context) { ctkDictionary properties; properties.insert(ctkPluginConstants::SERVICE_RANKING, 3); properties.insert("name", "Qui"); m_pImpl = new WelcomeQuiImpl(); context->registerService<WelcomeService>(m_pImpl, properties); } void WelcomeQuiActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) delete m_pImpl; }
#ifndef WELCOMEQUIIMPL_H #define WELCOMEQUIIMPL_H #include <QObject> #include "../../Service/welcome_service.h" class MainWindow; class WelcomeQuiImpl : public QObject, public WelcomeService { Q_OBJECT Q_INTERFACES(WelcomeService) public: explicit WelcomeQuiImpl(QObject *parent = nullptr); ~WelcomeQuiImpl(); void welcome() override; QWidget *widget() override; private: MainWindow *_mainwindow = nullptr; signals: }; #endif // WELCOMEQUIIMPL_H
#include "WelcomeQuiImpl.h" #include "MainWindow.h" #include <QDebug> WelcomeQuiImpl::WelcomeQuiImpl(QObject *parent) : QObject{parent} {} WelcomeQuiImpl::~WelcomeQuiImpl() { delete _mainwindow; } void WelcomeQuiImpl::welcome() { qDebug() << "welcome Qui"; } QWidget *WelcomeQuiImpl::widget() { _mainwindow = new MainWindow; return _mainwindow; }
Plugin-SymbolicName: Welcome.Qui
Plugin-ActivationPolicy: eager
Plugin-Category: Demos
Plugin-ContactAddress: https://github.com
Plugin-Description: A plugin for welcome Qui
Plugin-Name: WelcomeQui
Plugin-Vendor: shawn
Plugin-Version: 0.0.1
框架源码目录和插件源码目录的位置。service里面放的是引入ctk库的pri文件,用
qt5.15.2+vs2019
编译好的ctk的库放在源码的同级目录。bin是生成的目录,里面是exe和plugins文件夹,plugins文件夹里面是编好的插件库dll
不加载插件的时候,效果是这样的
加载插件后,效果是这样的
UI插件的widget已经被嵌入主界面中了
本demo完全参考博主
一去二三里
的开源代码实现。
参考:
https://blog.csdn.net/mr_robot_strange/category_11663281.html
https://github.com/Waleon/CTK-examples
https://www.cnblogs.com/judes/p/13285743.html
本篇文章对应demo地址:
https://download.csdn.net/download/yonug1107716573/88731039
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。