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_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    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_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
  • 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_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

  • 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Apache Doris 聚合函数源码阅读与解析|源码解读系列

笔者最近由于工作需要开始调研 Apache Doris&#xff0c;通过阅读聚合函数代码切入 Apache Doris 内核&#xff0c;同时也秉承着开源的精神&#xff0c;开发了 array_agg 函数并贡献给社区。笔者通过这篇文章记录下对源码的一些理解&#xff0c;同时也方便后面的新人更快速地上…

【Oracle】数据库对象

一、视图 1、视图概述 视图是一种数据库对象 视图 > 封装sql语句 > 虚拟表 2、视图的优点 简化操作&#xff1a;视图可以简化用户处理数据的方式。着重于特定数据&#xff1a;不必要的数据或敏感数据可以不出现在视图中。视图提供了一个简单而有效的安全机制&#x…

Odrive 学习系列一:vscode 编译Odrive

搭建环境可参考Markerbase教程,很详细了。 简单说一两点: 解压ODrive-fw-v0.5.1.zip: 打开ODrive-fw-v0.5.1文件夹,找到Firmware文件夹,用vscode打开该文件夹: 按照以下内容操作: 编译工程: 打开 中断(terminal),输入 make -j4 回车 进行编译。编译…

基于JavaWeb+BS架构+SpringBoot+Vue基于hive旅游数据的分析与应用系统的设计和实现

基于JavaWebBS架构SpringBootVue基于hive旅游数据的分析与应用系统的设计和实现 文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 文末获取源码 Lun文目录 1 概 述 5 1.1 研究背景 5 1.2 研究意义 5 1.3 研究内容…

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

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

python进行简单的app自动化测试(pywinauto)+ 截屏微信二维码

一、开始需要了解准备 1、安装 pip install pywinauto2、选择&#xff08;后面会通过工具进行判断用哪个&#xff09; 3、自动化控制进程的范围 示例 Application单进程 Desktop多进程 4、程序辅助检测工具 3中的下载连接 链接 点击放大镜拖到对应位置即可 二、简单的开始…

前端页面优化做的工作

1.分析模块占用空间 new (require(webpack-bundle-analyzer).BundleAnalyzerPlugin)() 2.使用谷歌浏览器中的layers&#xff0c;看下有没有影响性能的模块&#xff0c;或者应该销毁没销毁的 3.由于我们页面中含有很大的序列帧动画&#xff0c;所以会导致页面性能低&#xff0…

合并 K 个升序链表[困难]

一、题目 给你一个链表数组&#xff0c;每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 示例 1&#xff1a; 输入&#xff1a;lists [[1,4,5],[1,3,4],[2,6]] 输出&#xff1a;[1,1,2,3,4,4,5,6] 解释&#xff1a;链表数组如…

Maven 依赖管理项目构建工具 教程

Maven依赖管理项目构建工具 此文档为 尚硅谷 B站maven视频学习文档&#xff0c;由官方文档搬运而来&#xff0c;仅用来当作学习笔记用途&#xff0c;侵删。 另&#xff1a;原maven教程短而精&#xff0c;值得推荐&#xff0c;下附教程链接。 atguigu 23年Maven教程 目录 文章目…

2024-01-11 部署Stable Diffusion遇挫记

点击 <C 语言编程核心突破> 快速C语言入门 部署Stable Diffusion遇挫记 前言一、一如既往的GitHub部署二、使用的感受总结 create by Stable Diffusion; prompt: fire water llama 前言 要解决问题: 由于近期的努力, 已经实现语音转文字模型, 通用chat迷你大模型的本地…

适配 IOS 安全区域

安全区域指的是一个可视窗口范围&#xff0c;处于安全区域的内容不受圆角&#xff08;corners&#xff09;、齐刘海&#xff08;sensor housing&#xff09;、小黑条&#xff08;Home Indicator&#xff09;影响。 造成这个问题的主要原因就是 iphoneX 之后在屏幕上出现了所谓…

Swoft - Bean

一、Bean 在 Swoft 中&#xff0c;一个 Bean 就是一个类的一个对象实例。 它(Bean)是通过容器来存放和管理整个生命周期的。 最直观的感受就是省去了频繁new的过程&#xff0c;节省了资源的开销。 二、Bean的使用 1、创建Bean 在【gateway/app/Http/Controller】下新建一个名为…

鸿蒙HarmonyOS兼容JS的类Web开发-开发指导

鸿蒙HarmonyOS兼容JS的类Web开发-开发指导 文章目录 鸿蒙HarmonyOS兼容JS的类Web开发-开发指导常用组件开发指导list开发指导创建list组件添加滚动条添加侧边索引栏实现列表折叠和展开场景示例 dialog开发指导创建dialog组件设置弹窗响应场景示例 form开发指导创建form组件实现…

经管类CSSCI、北核期刊投稿指南数据(2023年更新)/经管类的期刊投稿指南

经管类CSSCI、北核期刊投稿指南&#xff08;2023年更新&#xff09; 1、内容包括&#xff1a;投稿指南-CSSCI版本、CSSCI扩展版本、北大核刊版本、建议期刊版本、所有期刊。 2、范围&#xff1a;CSSCI、CSSCI扩展、北大核刊 3、说明&#xff1a;包含经管类期刊的发表难度&am…

css3边框与圆角

css3边框与圆角 前言边框的三要素边框的三要素小属性 四个方向的边框四个方向边框的三要素小属性 去掉边框利用边框制作三角形圆角 border-radius单独设置四个圆角小属性百分比为单位 盒子阴影阴影延展内阴影多阴影 结语 前言 在网页设计中&#xff0c;边框与圆角不仅仅是简单…

FAST OS DOCKER 可视化Docker管理工具

介绍 FAST OS DOCKER 界面直观、简洁&#xff0c;非常适合新手使用&#xff0c;方便大家轻松上手 docker部署运行各类有趣的容器应用&#xff0c;同时 FAST OS DOCKER 为防止服务器负载过高&#xff0c;进行了底层性能优化&#xff1b;其以服务器安全为基础&#xff0c;对其进…

天津大数据分析培训班 常见的大数据培训课程

大数据现在属于热门职业技能之一&#xff0c;不管是大学毕业生&#xff0c;计算机和数据相关专业青年&#xff0c;已经工作一阵的开发人员&#xff0c;运营小白&#xff0c;还是其他想进入这个行当的&#xff0c;可能还没有编程基础的转行人&#xff0c;都想尝试大数据行业&…

联手英特尔,释放星飞分布式全闪存储潜能

近日&#xff0c;英特尔官网发布了与 XSKY 星辰天合联手打造的解决方案&#xff0c;即 XSKY 的新一代全闪分布式存储系统 XINFINI&#xff0c;该存储系统采用英特尔 QAT 加速数据压缩/解压缩&#xff0c;从而大幅度提升存储系统性能。 全闪存储系统面临的解压缩挑战 在存储系统…

【开源】基于JAVA+Vue+SpringBoot的大病保险管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统配置维护2.2 系统参保管理2.3 大病保险管理2.4 大病登记管理2.5 保险审核管理 三、系统详细设计3.1 系统整体配置功能设计3.2 大病人员模块设计3.3 大病保险模块设计3.4 大病登记模块设计3.5 保险审核模块设计 四、…

Java21 如何使用switch case

1. Java8 和 Java21 Java8 引入字符串和枚举 Java21 可以返回值, yield关键字, switch 表达式, 模式匹配, null值处理 2. 代码案例 1. Java8 public static void java8() {String day "tuesday";switch (day) {case "monday":System.out.println("w…