CTK框架介绍和环境搭建

CTK框架介绍和环境搭建

概述

本人第一次接触CTK的时候是看的一去、二三里大佬的博客。

  1. CTK框架实际应用比较可靠,但网上资料很少,官网提供的API链接也已经无法打开了,目前还没有找到很好的官方的使用介绍。
  2. 网上目前找到的CTK的介绍或者是博客都没有非常具体的项目,都是一些简单的demo。
  3. 按照下面列出的参考的文档和大佬们的博客,来写代码的时候会碰到一些奇奇怪怪的问题,我这里也是重写一下这个框架的介绍和基本的使用方法,方便后来的人使用。

本篇文章参考的: 来唧唧歪歪

环境准备

CTK介绍

CTK 为支持生物医学图像计算的公共开发包,其全称为 Common Toolkit。CTK插件框架的设计有很大的灵感来自OSGi并且使得应用程序由许多不同的组件组合成一个可扩展模型。这个模型允许通过那些组件间共享对象的服务通信。

当前,CTK 工作的主要范围包括:

  • DICOM:提供了从 PACS 和本地数据库中查询和检索的高级类。包含 Qt 部件,可以轻松地设置服务器连接,并发送查询和查看结果。
  • DICOM Application Hosting:目标是创建 DICOM Part 19 Application Hosting specifications 的 C++ 参考实现。它提供了用于创建主机和托管应用程序的基础设。
  • Widgets:用于生物医学成像应用的 Qt Widgets 集合。
  • Plugin Framework:用于 C++ 的动态组件系统,以 OSGi 规范为模型。它支持一个开发模型,在这个模型中,应用程序(动态地)由许多不同(可重用的)组件组成,遵循面向服务的方法。
  • Command Line Interfaces:一种允许将算法编写为自包含可执行程序的技术,可以在多个终端用户应用程序环境中使用,而无需修改。

使用 CTK Plugin Framework 的好处

由于 CTK Plugin Framework 基于 OSGi,因此它继承了一种非常成熟且完全设计的组件系统,这在 Java 中用于构建高度复杂的应用程序,它将这些好处带给了本地(基于 Qt 的)C++ 应用程序,并适应于 CTK Plugin Framework:。

以下内容摘自 《OSGi官方文档》 (aliyun.com),并且做了一定的修改:

  • 降低复杂性

    使用 CTK Plugin Framework 开发意味着开发插件,它们隐藏了内部实现,并通过定义良好的服务来和其它插件通信。隐藏内部机制意味着以后可以自由地更改实现,这不仅有助于 Bug 数量的减少,还使得插件的开发变得更加简单,因为只需要实现已经定义好的一定数量的功能接口即可。

  • 复用

    使用 CTK Plugin Framework 开发意味着,我们可以规定标准化的组件模型,使得在应用程序中使用第三方组件变得非常容易。

  • 现实情况

    CTK Plugin Framework 是一个动态框架,它可以动态地更新插件和服务。在现实世界中,有很多场景都和动态服务模型相匹配。因此,应用程序可以在其所属的领域中重用 Service Registry 的强大基元(注册、获取、用富有表现力的过滤语言列表、等待服务的出现和消失)。这不仅节省了编写代码,还提供了全局可见性、调试工具以及比为专用解决方案实现的更多的功能。在这样的动态环境下编写代码听起来似乎是个噩梦,但幸运的是,有支持类和框架可以消除大部分(如果不是全部的话)痛苦。

  • 开发简单

    CTK Plugin Framework 不仅仅是组件的标准,它还指定了如何安装和管理组件。标准化的管理 API 使得在现有和未来的系统中集成 CTK Plugin Framework 变得非常容易。

  • 动态更新

    CTK Plugin Framework 组件模型是一个动态模型,插件可以在不关闭整个系统的情况下被安装、启动、停止、更新和卸载。

  • 自适应

    OSGi 组件模型是从头设计的,以允许组件的混合和匹配。这就要求必须指定组件的依赖关系,并且需要组件在其可选依赖性并不总是可用的环境中生存。Service Registry 是一个动态注册表,其中插件可以注册、获取和监听服务。这种动态服务模型允许插件找出系统中可用的功能,并调整它们所能提供的功能。这使得代码更加灵活,并且能够更好地适应变化。

  • 透明性

    插件和服务在CTK 插件环境中是最高级的。管理 API 提供了对插件的内部状态的访问,以及插件之间的连接方式。可以停止部分应用程序来调试某个问题,或者可以引入诊断插件。

  • 版本控制

    在 CTK Plugin Framework 中,所有的插件都经过严格的版本控制,只有能够协作的插件才会被连接在一起。

  • 简单

    CTK 插件相关的 API 非常简单,核心 API 不到 25 个类。这个核心 API 足以编写插件、安装、启动、停止、更新和卸载它们,并且还包含了所有的监听类。

  • 懒加载

    懒加载是软件中一个很好的点,OSGi 技术有很多的机制来保证只有当类真正需要的时候才开始加载它们。例如,插件可以用饿汉式启动,但是也可以被配置为仅当其它插件使用它们时才启动。服务可以被注册,但只有在使用时才创建。这些懒加载场景,可以节省大量的运行时成本。

  • 非独占性

    CTK Plugin Framework 不会接管整个应用程序,你可以选择性地将所提供的功能暴露给应用程序的某些部分,或者甚至可以在同一个进程中运行该框架的多个实例。

  • 非侵入

    在一个 CTK 插件环境中,不同插件均有自己的环境。它们可以使用任何设施,框架对此并无限制。CTK 服务没有特殊的接口需求,每个 QObject 都可以作为一个服务,每个类(也包括非 QObject)都可以作为一个接口。

CTK的项目结构

我这里使用的是CMake对项目进行管理的,因此我这边直接贴出CMake代码

主项目的代码

CMakeLists.txt

cmake_minimum_required(VERSION 3.19)
project(CTKPlugin)
# debug需要覆盖对应的dll, 并且需要删除configuration文件夹,让它重新生成
# 指定C++标准
set(CMAKE_CXX_STANDARD 17)
# 指定输出目录
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/output)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/output)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/output)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/output)
# 自动编译QT文件
# set(CMAKE_PREFIX_PATH "C:/Qt/6.5.1/msvc2019_64")
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
# 开启包含当前编译目录
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 指定QT版本和对应的库
set(QT_VERSION 5)
set(REQUIRED_LIBS Core Gui Widgets OpenGL Sql
#        Core5Compat
        )
set(REQUIRED_LIBS_QUALIFIED Qt${QT_VERSION}::Core Qt${QT_VERSION}::Gui Qt${QT_VERSION}::Widgets Qt${QT_VERSION}::OpenGL Qt${QT_VERSION}::Sql
#        Qt${QT_VERSION}::Core5Compat
        )
# 包含的插件项目目录
add_subdirectory(core)
# 寻找QT库
find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} REQUIRED)
# 包含的头文件目录
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src
        ${CMAKE_CURRENT_SOURCE_DIR}/third_party/CTK/include/ctk-0.1
        ${CMAKE_CURRENT_SOURCE_DIR}/third_party/qmqtt/include
        )
# 需要编译的头文件
file(GLOB HEADERS
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h
        )
# 需要编译的cpp文件
file(GLOB SOURCES
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
        )
# 需要编译的ui文件
file(GLOB UIS
        ${CMAKE_CURRENT_SOURCE_DIR}/src/*.ui
        )
# 根据不同的模式加载不同的CTK库(DEBUG和RELEASE)
if (CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Debug"))
    file(GLOB LIB_CTK ${PROJECT_SOURCE_DIR}/third_party/CTK/libd/ctk-0.1/*.lib)
    link_directories(${PROJECT_SOURCE_DIR}/third_party/CTK/libd/ctk-0.1)
else ()
    file(GLOB LIB_CTK ${PROJECT_SOURCE_DIR}/third_party/CTK/lib/ctk-0.1/*.lib)
    link_directories(${PROJECT_SOURCE_DIR}/third_party/CTK/lib/ctk-0.1)
endif ()
# 指定格式为utf-8
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
# 使用指定的源文件来生成目标可执行文件
add_executable(${PROJECT_NAME} WIN32 main.cpp ${HEADERS} ${SOURCES} ${UIS})
target_link_libraries(${PROJECT_NAME} ${REQUIRED_LIBS_QUALIFIED} ${LIB_CTK} ${LIB_MQTT})

main.cpp

#include <QApplication>
#include <iostream>
#include <QStyleFactory>
#include <QDir>
#include <QDirIterator>
#include "ctkPluginFrameworkFactory.h"
#include "ctkPluginFramework.h"
#include "ctkPluginException.h"
#include "ctkPluginContext.h"
#include "ctkPluginFrameworkLauncher.h"
#include "imainwindow.h"

int main(int argc, char* argv[])
{
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);
    app.setApplicationName("ctktest");
    QString path = QCoreApplication::applicationDirPath();
    // 在插件的搜索路径列表中添加一条路径
#ifdef _DEBUG
    ctkPluginFrameworkLauncher::addSearchPath(path + "/libs/debug");
#else
    ctkPluginFrameworkLauncher::addSearchPath(path + "/libs/release");
#endif // _DEBUG
    // 设置并启动 CTK 插件框架
    try {
        ctkPluginFrameworkLauncher::start("org.commontk.eventadmin");
    }
    catch (ctkException e)
    {
        std::cout << e.message().toStdString() << std::endl;
    }
    // 启动插件工厂
    ctkPluginFrameworkFactory* ctkFrameWorkFactory = new ctkPluginFrameworkFactory;
    QSharedPointer<ctkPluginFramework> framework= ctkFrameWorkFactory->getFramework();
    try{
        framework->init();
        framework->start();
    }
    catch(const ctkPluginException& e)
    {
        std::cout << "framework init fail" << std::endl;
    }
    return app.exec();
}

以上只要可以将插件的工厂正常启动则表示插件库加载完成。

注意: ctkPluginFrameworkFactory* ctkFrameWorkFactory = new ctkPluginFrameworkFactory;

这边我看基本上所有的教程中都是这么写的ctkPluginFrameworkFactory ctkFrameWorkFactory而我这边给换成了指针。这个是一个小坑,我踩了因此这边也给到一个特殊标注。如果是使用的临时变量,临时变量在main函数退出的时候会析构,这里可能是因为ctkFrameWorkFactory析构太早的问题,导致整个程序在最后退出的时候崩溃,如果换成指针则让程序完成退出之后收回内存,这样不会产生因ctkFrameWorkFactory析构而退出崩溃的问题。

或者是什么其他原因呢?这个地方有没有大佬可以帮忙指正一下,因为除了这种方式以外,我没有找到比较好的方式去解决这个问题造成的崩溃。

Core插件的代码

Core插件和主程序的CMake在同级目录即可。

CMakeLists.txt

cmake_minimum_required(VERSION 3.19)
project(Core)
#指定C++标准
set(CMAKE_CXX_STANDARD 17)
#指定输出目录,这里将插件输出到统一的目录方便后续的加载工作
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/../output/plugins)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/../output/plugins)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/../output/plugins)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/../output/plugins)
#自动编译QT文件
#set(CMAKE_PREFIX_PATH "C:/Qt/6.5.1/msvc2019_64")
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
#开启包含当前编译目录
set(CMAKE_INCLUDE_CURRENT_DIR ON)
#指定QT版本和对应的库
set(QT_VERSION 5)
set(REQUIRED_LIBS Core Gui Widgets Network WebEngineCore WebEngineWidgets
#        Core5Compat
        )
set(REQUIRED_LIBS_QUALIFIED Qt${QT_VERSION}::Core Qt${QT_VERSION}::Gui Qt${QT_VERSION}::Widgets Qt${QT_VERSION}::Network Qt${QT_VERSION}::WebEngineCore Qt${QT_VERSION}::WebEngineWidgets
#        Qt${QT_VERSION}::Core5Compat
        )
#寻找QT库
find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} REQUIRED)
# 这里又包含了一个子项目
add_subdirectory(QCodeEditor)

include_directories(src
        ../third_party/CTK/include/ctk-0.1
        ../third_party/qadvance/include
        QCodeEditor/include
        )
file(GLOB HEADERS
        src/*.h
        )
file(GLOB SOURCES
        src/*.cpp
        )

file(GLOB UIS
        src/*.ui
        )
# 指定格式为utf-8
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")

if (CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Debug"))
    file(GLOB LIB_CTK ${PROJECT_SOURCE_DIR}/../third_party/CTK/libd/ctk-0.1/*.lib)
    link_directories(${PROJECT_SOURCE_DIR}/../third_party/CTK/libd/ctk-0.1)
    file(GLOB LIB_ADVANCEDOC ${PROJECT_SOURCE_DIR}/../third_party/qadvance/libd/*.lib)
    link_directories(${PROJECT_SOURCE_DIR}/../third_party/qadvance/libd)
else ()
    file(GLOB LIB_CTK ${PROJECT_SOURCE_DIR}/../third_party/CTK/lib/ctk-0.1/*.lib)
    link_directories(${PROJECT_SOURCE_DIR}/../third_party/CTK/lib/ctk-0.1)
    file(GLOB LIB_ADVANCEDOC ${PROJECT_SOURCE_DIR}/../third_party/qadvance/lib/*.lib)
    link_directories(${PROJECT_SOURCE_DIR}/../third_party/qadvance/lib)
endif ()

#使用指定的源文件来生成目标可执行文件
add_library(${PROJECT_NAME} SHARED resources.qrc resources2.qrc ${HEADERS} ${SOURCES} ${UIS})
target_link_libraries(${PROJECT_NAME} ${REQUIRED_LIBS_QUALIFIED} ${LIB_CTK} ${LIB_ADVANCEDOC} QCodeEditor)

本篇文章先写到这,后续会出更加详细的介绍

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
CTK(Common Toolkit)是一个基于Qt的开源框架,旨在为医学图像处理和分析提供易于使用的工具。以下是在C++ Qt中搭建CTK框架的步骤: 1. 下载CTK框架 可以从CTK官网下载CTK框架。下载后,解压缩文件到本地文件夹。 2. 在Qt中添加CTK框架Qt中选择菜单栏的“项目”->“添加库”,然后选择“外部库”->“Qt添加库向导”。在向导中,选择“静态库”,然后选择CTK框架的文件夹路径。在完成添加后,确保在项目文件中包含CTK库的头文件和库文件。 3. 创建CTK模块 在Qt中创建一个新的Qt工程,并添加一个CTK模块。在项目视图中,右键单击项目并选择“添加新项”,然后选择“CTK模块”。在向导中,输入模块名称和模块路径,选择要使用的模块类型。在完成向导后,Qt将自动创建一个CTK模块,并将其添加到项目中。 4. 编写CTK插件 在CTK模块中,可以创建一个或多个CTK插件。CTK插件是可加载的Qt插件,用于扩展应用程序的功能。在Qt中创建一个新的Qt工程,并添加一个CTK插件。在项目视图中,右键单击项目并选择“添加新项”,然后选择“CTK插件”。在向导中,输入插件名称和插件路径,选择要使用的插件类型。在完成向导后,Qt将自动创建一个CTK插件,并将其添加到项目中。 5. 将CTK插件添加到应用程序中 在应用程序中,可以通过加载CTK插件来添加新功能。在Qt中,可以使用QPluginLoader类来加载CTK插件。使用QPluginLoader类加载CTK插件后,可以使用插件的接口来访问其功能。 以上就是在C++ Qt中搭建CTK框架的基本步骤。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

turbolove

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值