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.mzph.cn/news/622435.shtml

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

相关文章

4D 毫米波雷达:智驾普及的新路径(二)

4 4D 毫米波的技术路线探讨 4.1 前端收发模块 MMIC&#xff1a;级联、CMOS、AiP 4.1.1 设计&#xff1a;级联、单芯片、虚拟孔径 4D 毫米波雷达的技术路线主要分为三种&#xff0c;分别是多级联、级联 虚拟孔径成像技术、以及 集成芯片。&#xff08; 1 &#xff09;多级…

一张图总结架构设计的40个黄金法则

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;很多小伙伴拿到非常优质的架构机会&#xff0c;常常找尼恩求助&#xff1a; 尼恩&#xff0c;我这边有一个部门技术负责人资深架构师的机会&#xff0c;非常难得&#xff0c; 但是有一个大厂高P在抢&#xff0…

第18课 移植FFmpeg和openCV到Android环境

要在Android下从事音视频开发&#xff0c;同样也绕不开ffmpegopencv&#xff0c;不管是初学者还是有一定经验的程序&#xff0c;面临的首要问题就是环境的搭建和库文件的编译配置等问题&#xff0c;特别是初学者&#xff0c;往往会在实际开发前浪费大量的时间来编译ffmpeg及ope…

【前后端的那些事】开源!前后端环境搭建+树形结构表格实现

文章目录 1. 前后端项目环境搭建2. table-tree2.1 后端准备2.2 前端准备 前言&#xff1a;最近写项目&#xff0c;发现了一些很有意思的功能&#xff0c;想写文章&#xff0c;录视频把这些内容记录下。但这些功能太零碎&#xff0c;如果为每个功能都单独搭建一个项目&#xff0…

py连接sqlserver数据库报错问题处理。20009

报错 pymssql模块连接sqlserver出现如下错误&#xff1a; pymssql._pymssql.OperationalError) (20009, bDB-Lib error message 20009, severity 9:\nUnable to connect: Adaptive Server is unavailable or does not exist (passwordlocalhost)\n) 解决办法&#xff1a; 打…

ES搜索的安装以及常用的增删改查操作(已经写好json文件,可以直接使用)

1.es的下载 https://www.elastic.co/cn/downloads/past-releases 2.elasticsearch安装及配置&#xff0c;遇到9200访问不了以及中文乱码&#xff0c;能访问了却要账户密码等问题 Elasticsearch启动后访问9200失败_http://localhost:9200无返回值-CSDN博客 3.开启es服务&#x…

ZZULIOJ 1112: 进制转换(函数专题)

题目描述 输入一个十进制整数n&#xff0c;输出对应的二进制整数。常用的转换方法为“除2取余&#xff0c;倒序排列”。将一个十进制数除以2&#xff0c;得到余数和商&#xff0c;将得到的商再除以2&#xff0c;依次类推&#xff0c;直到商等于0为止&#xff0c;倒取除得的余数…

C语言中关于指针的理解及用法

关于指针意思的参考&#xff1a;https://baike.baidu.com/item/%e6%8c%87%e9%92%88/2878304 指针 指针变量 地址 野指针 野指针就是指针指向的位置是不可知的&#xff08;随机的&#xff0c;不正确的&#xff0c;没有明确限制的&#xff09; 以下是导致野指针的原因 1.指针…

mysql原理--redo日志1

1.redo日志是个啥 我们知道 InnoDB 存储引擎是以页为单位来管理存储空间的&#xff0c;我们进行的增删改查操作其实本质上都是在访问页面&#xff08;包括读页面、写页面、创建新页面等操作&#xff09;。我们前边唠叨 Buffer Pool 的时候说过&#xff0c;在真正访问页面之前&a…

Hyperledger Fabric 通道配置文件解析

fabric 版本 v2.4.1 Fabric 网络是分布式系统&#xff0c;采用通道配置&#xff08;Channel Configuration&#xff09;来定义共享账本的各项行为。通道配置的管理对于网络功能至关重要。 通道配置一般包括通道全局配置、排序配置和应用配置等多个层级&#xff0c;这些配置都存…

好物周刊#36:程序员简历

村雨遥的好物周刊&#xff0c;记录每周看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;每周五发布。 一、项目 1. SmartDNS 一个运行在本地的 DNS 服务器&#xff0c;它接受来自本地客户端的 DNS 查询请求&#xff0c;然后从多个上游 DNS 服务器获取 DNS 查询…

JavaScript学习笔记——变量、作用域、var、const和let

JavaScript学习笔记——变量、作用域、var、const和let 学习链接&#xff08;原链接&#xff09;变量变量声明的三种方式 作用域作用域介绍作用域分类全局作用域局部作用域&#xff08;函数作用域&#xff09;块级作用域块级作用域和局部(函数)作用域区别 varvar的作用域(全局函…

单表的查询练习

一、单表查询 素材&#xff1a; 表名&#xff1a;worker-- 表中字段均为中文&#xff0c;比如 部门号 工资 职工号 参加工作 等 显示所有职工的基本信息。 mysql8.0 [chap03]>select * from worker; 查询所有职工所属部门的部门号&#xff0c;不显示重复的部门号。 mysq…

SOLID 原则

单一功能原则 单一功能原则&#xff08;Single responsibility principle&#xff09;规定每个类都应该有一个单一的功能&#xff0c;并且该功能应该由这个类完全封装起来。所有它的&#xff08;这个类的&#xff09;服务都应该严密的和该功能平行&#xff08;功能平行&#x…

AnyDoor任意门:零样本物体级图像定制化

文章目录 一、AnyDoor简介二、AnyDoor方法&#xff08;一&#xff09;ID特征提取&#xff08;二&#xff09;细节特征提取&#xff08;三&#xff09;特征注入&#xff08;四&#xff09;视频、图像动态采样 一、AnyDoor简介 “任意门”算法&#xff1a;可以将任意目标传送到指…

Java SPI机制总结系列之开发入门实例

原创/朱季谦 在该文章正式开始前&#xff0c;先对 Java SPI是什么做一个简单的介绍。 SPI&#xff0c;是Service Provider Interface的缩写&#xff0c;即服务提供者接口&#xff0c;单从字面上看比较抽象&#xff0c;你可以理解成&#xff0c;该机制就像Spring容器一样&…

Python之Matplotlib绘图调节清晰度

Python之Matplotlib绘图调节清晰度 文章目录 Python之Matplotlib绘图调节清晰度引言解决方案dpi是什么&#xff1f;效果展示总结 引言 使用python中的matplotlib.pyplot绘图的时候&#xff0c;如果将图片显示出来&#xff0c;或者另存为图片&#xff0c;常常会出现清晰度不够的…

【JAVA】在 Queue 中 poll()和 remove()有什么区别

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 poll() 方法&#xff1a; remove() 方法&#xff1a; 区别总结&#xff1a; 结语 我的其他博客 前言 在Java的Queue接口中&…

强化学习应用(六):基于Q-learning的物流配送路径规划研究(提供Python代码)

一、Q-learning算法简介 Q-learning是一种强化学习算法&#xff0c;用于解决基于马尔可夫决策过程&#xff08;MDP&#xff09;的问题。它通过学习一个值函数来指导智能体在环境中做出决策&#xff0c;以最大化累积奖励。 Q-learning算法的核心思想是使用一个Q值函数来估计每…

day-09 删除排序链表中的重复元素

思路 从前往后遍历链表&#xff0c;当当前节点的值与下一个节点值相等时&#xff0c;删除下一节点&#xff1b;否则向后移动一个节点&#xff0c;继续遍历 解题方法 while(p!null&&p.next!null){ if(p.next.valp.val)p.nextp.next.next;//当前节点的值与下一个节点值相…