Qt框架学习 --- CTK

系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 一、准备阶段
  • 二、使用介绍
    • 1.核心思想
    • 2.源码
      • 2.1.框架部分资源目录树
      • 2.2.框架部分源码
      • 2.3.插件部分资源目录树
      • 2.4.插件部分源码
    • 3.文件结构
    • 4.运行效果
  • 总结


前言

随着开发的深入,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的一个模块更改的。

二、使用介绍

1.核心思想

ctk框架核心主要有2点:框架和插件。框架加载插件,之间的通讯使用事件或者信号槽。

2.源码

2.1.框架部分资源目录树

在这里插入图片描述

2.2.框架部分源码

框架的核心就是框架和需要调用的服务类(一个纯虚类,同插件共用一个)

  • App.pro
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.pri
# 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
  • MainWindow.h
 #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
  • MainWindow.cpp
#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);}
}
  • main.cpp
#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();
}
  • MainWindow.ui

在这里插入图片描述

2.3.插件部分资源目录树

在这里插入图片描述

2.4.插件部分源码

插件的核心就是实现类(实现一个纯虚类,框架只调用纯虚类的方法 )和激活类。就拿WelcomeQui举例吧

  • WelcomeQui.pro
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
  • MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
  • MainWindow.cpp
#include "MainWindow.h"
#include "ui_MainWindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);
}MainWindow::~MainWindow()
{delete ui;
}
  • WelcomeQuiActivator.h 激活类
#ifndef WELCOMEQUIACTIVATOR_H
#define WELCOMEQUIACTIVATOR_H#include <QObject>
#include <ctkPluginActivator.h>class WelcomeQuiImpl;class WelcomeQuiActivator : public QObject, public ctkPluginActivator
{Q_OBJECTQ_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
  • WelcomeQuiActivator.cpp
#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;
}
  • WelcomeQuiImpl.h 实现类
#ifndef WELCOMEQUIIMPL_H
#define WELCOMEQUIIMPL_H#include <QObject>
#include "../../Service/welcome_service.h"class MainWindow;class WelcomeQuiImpl : public QObject, public WelcomeService
{Q_OBJECTQ_INTERFACES(WelcomeService)public:explicit WelcomeQuiImpl(QObject *parent = nullptr);~WelcomeQuiImpl();void welcome() override;QWidget *widget() override;private:MainWindow *_mainwindow = nullptr;
signals:
};#endif // WELCOMEQUIIMPL_H
  • WelcomeQuiImpl.cpp
#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;
}
  • MainWindow.ui

在这里插入图片描述- MANIFEST.MF

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

3.文件结构

框架源码目录和插件源码目录的位置。service里面放的是引入ctk库的pri文件,用qt5.15.2+vs2019编译好的ctk的库放在源码的同级目录。bin是生成的目录,里面是exe和plugins文件夹,plugins文件夹里面是编好的插件库dll

在这里插入图片描述

4.运行效果

不加载插件的时候,效果是这样的

在这里插入图片描述
在这里插入图片描述

加载插件后,效果是这样的

在这里插入图片描述
在这里插入图片描述

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

陶瓷碗口缺口检测-图像获取与图像复原

图像获取 在陶瓷产品传送带上安装数据采集设备&#xff0c;如工业摄像头&#xff0c;进行图像数据采集。为提高陶瓷的检测精度&#xff0c;同时考虑到开发成本等问题采用高精度的CMOS工业摄像头进行数据采集。对图像进行灰度化处理&#xff0c; 图a为采集到的原彩色图像&#…

如何使用提示压缩来削减 RAG 80% 成本

每日推荐一篇专注于解决实际问题的外文,精准翻译并深入解读其要点,助力读者培养实际问题解决和代码动手的能力。 欢迎关注公众号(NLP Research) 原文标题:How to Cut RAG Costs by 80% Using Prompt Compression 原文地址:https://medium.com/towards-data-science/how…

Linux文件系统的层次结构、每个目录的含义、文件属性以及文件中第一列的第一个字符的含义

1.Linux文件系统的层次结构 在Linux操作系统中&#xff0c;所有的文件和目录都被组织成以一个根节点“/”开始的导致的树状结构&#xff1a; 5.Linux系统的目录解析 &#xff08;1&#xff09;/bin bin是Binary的缩写&#xff0c;这个目录存放着最经常使用的命令。 &#x…

UIUC CS241 讲义:众包系统编程书

原文&#xff1a;angrave/SystemProgramming 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 欢迎来到 Angrave 的众包系统编程维基书&#xff01;这个维基是由伊利诺伊大学的学生和教师共同建立的&#xff0c;是伊利诺伊大学 CS 的 Lawrence Angrave 的众包创作实验。…

C# FreeSql使用,基于Sqlite的DB Frist和Code First测试

文章目录 前言FreeSql 简单连接数据库服务不存在没装FreeSql.All装了FreeSql.All安装包选择 DBFirst安装命令行生成器生成Bat创建脚本 基于Sqlite的Code Frist文件夹自动导出到Debug目录Sqlite 数据库安装和创建Sqlite连接数据库自动增列增表测试增列删列改列名同名列改属性 Co…

基于Vue组合式API的实用工具集

简介 今天,给大家分享一个很实用的工具库 VueUse,它是基于 Vue Composition Api,也就是组合式API。支持在Vue2和Vue3项目中进行使用,据说是目前世界上Star最高的同类型库之一。 图片 官方地址:https://vueuse.org/ 中文地址:https://www.vueusejs.com/ github:https…

邂逅Node.JS的那一夜

邂逅Node.JS的那一夜&#x1f303; 本篇文章&#xff0c;学习记录于&#xff1a;尚硅谷&#x1f3a2; 本篇文章&#xff0c;并不完全适合小白&#xff0c;需要有一定的HTML、CSS、JS、HTTP、Web等知识及基础学习&#xff1a; &#x1f197;&#xff0c;紧接上文&#xff0c;…

SQL-分页查询and语句执行顺序

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;重拾MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出现错误&am…

SQL-条件查询与聚合函数的使用

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;重拾MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出现错误&am…

uniapp中uview组件库丰富的ActionSheet 操作菜单使用方法

目录 #平台差异说明 #基本使用 #配置顶部的提示信息和底部取消按钮 #如何知道点了第几项 #API #Props #Event 本组件用于从底部弹出一个操作菜单&#xff0c;供用户选择并返回结果。 本组件功能类似于uni的uni.showActionSheetAPI&#xff0c;配置更加灵活&#xff0c;所…

Realm Management Extension领域管理扩展之颗粒保护检查

本节描述了RME引入的颗粒保护检查。颗粒保护检查使得能够在不同的物理地址空间之间动态分配内存区域。 本节将向您介绍以下功能: 颗粒保护表的结构用于颗粒保护检查的故障报告区域在物理地址空间之间的过渡正如在物理地址一节中所述,RME提供了四个物理地址空间。以下图表显示…

GEE数据集——2000 年至 2022 年与传感器无关的 MODIS 和 VIIRS LAI/FPAR CDR

2000 年至 2022 年与传感器无关的 MODIS 和 VIIRS LAI/FPAR CDR 该地理空间数据集包含关键的生物物理参数&#xff0c;即叶面积指数&#xff08;LAI&#xff09;和光合有效辐射分量&#xff08;FPAR&#xff09;&#xff0c;是描述陆地生态系统特征不可或缺的参数。该数据集解…