Agent skill

Create Cpp Plugin

by czyt1988 in czyt1988/data-workbench

A skill your agent uses when creating a new C++ plugin DLL for the data-workbench platform, or modifying an existing plugin's structure, CMake, UI integration, or data access.

LGPL-3.0Auto-check passedData & Analytics

Install Create Cpp Plugin

skills CLI
$ npx skills add czyt1988/data-workbench --skill create-cpp-plugin -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install czyt1988/data-workbench create-cpp-plugin --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/czyt1988/data-workbench.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/create-cpp-plugin .claude/skills/create-cpp-plugin && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
create-cpp-plugin
GitHub stars
102
Token cost
~5.5k tokens
SKILL.md length
300 words
Files
1
Skills in repo
4
Repo updated
First seen
Licence
LGPL-3.0

At a glance

A skill your agent uses when creating a new C++ plugin DLL for the data-workbench platform, or modifying an existing plugin's structure, CMake, UI integration, or data access.

  • Works in 8 steps: 必须先构建 data-workbench 子模块 — 插件依赖… → 使用 Visual Studio 生成器 — 不要用… → 构建类型必须一致 — 插件的 --config 参数必须与… → …
  • Creating a new C++ plugin DLL for the data-workbench platform
  • SKILL.md covers 决策树, 架构概览, 场景 A:完整插件骨架 and 场景 B:UI 集成, plus 7 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Create Cpp Plugin is an agent skill from czyt1988/data-workbench. Use when creating a new C++ plugin DLL for the data-workbench platform, or modifying an existing plugin's structure, CMake, UI integration, or data access. Triggers: create plugin, new plugin, DAAbstractNodePlugin, plugin CMake, ribbon category, dock widget, DAWorkbench plugin, plugin skeleton.

Its SKILL.md is about 5.5k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Data & Analytics. It works with C++. The repository describes itself as: AI Agent-driven data analysis workbench built on C++17/Qt: directed-graph workflow engine, embedded Python (pandas/numpy), interactive publication-quality charts, C++ & Python… The licence is LGPL-3.0.

When your agent uses it

  • Creating a new C++ plugin DLL for the data-workbench platform
  • Modifying an existing plugins structure

Example prompts

  • “/create-cpp-plugin”

Requirements

  • Python 3

Workflow steps

8 steps, taken from the first numbered list in SKILL.md.

  1. 必须先构建 data-workbench 子模块 — 插件依赖 daworkbench_plugin_utils.cmake 和所有 DAWorkbench 库
  2. 使用 Visual Studio 生成器 — 不要用 Ninja,PowerShell 中 MSVC 环境无法正确注入
  3. 构建类型必须一致 — 插件的 --config 参数必须与 data-workbench 一致(Release/Debug)
  4. DAWidgets 需显式 find_package — DAGui 依赖 DAWidgets,但 DAWorkbenchConfig 不会自动加载它
  5. Q_PLUGIN_METADATA 必须正确 — IID 必须是 DAABSTRACTNODEPLUGIN_IID
  6. 插件类必须同时继承 QObject 和 DAAbstractNodePlugin — QObject 必须是第一个基类
  7. DLL 直接输出到 plugins 目录 — 通过 RUNTIME_OUTPUT_DIRECTORY 设置,非 install 阶段
  8. Python 脚本通过 file(COPY) 部署 — CMake 配置阶段自动复制到 bin/PyScripts/,修改 .py 后需重新 CMake configure 或手动复制

What it can do on your machine

Read from SKILL.md and the folder at commit cf3bbda. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are cpp and cmake).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Create Cpp Plugin loads about 5.5k tokens when it runs. Until then it costs about 78 tokens; SKILL.md has 300 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~78
When it runs · the whole SKILL.md, loaded when a task matches
~5.5k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from czyt1988/data-workbench at commit cf3bbda, republished under its LGPL-3.0 licence (© czyt1988). 300 words, ~5,489 tokens.

Download SKILL.mdSave it as .claude/skills/create-cpp-plugin/SKILL.md (or your agent's skills folder).
name
create-cpp-plugin
description
Use when creating a new C++ plugin DLL for the data-workbench platform, or modifying an existing plugin's structure, CMake, UI integration, or data access. Triggers: create plugin, new plugin, DAAbstractNodePlugin, plugin CMake, ribbon category, dock widget, DAWorkbench plugin, plugin skeleton.

创建 data-workbench C++ 插件

本技能指导如何基于 DAWorkbench 平台框架创建 C++ 插件 DLL,涵盖插件骨架、CMake 配置、UI 集成(Ribbon/Dock)、数据访问、工程存档等完整流程。

决策树

你要做什么?
├── 从零创建一个新插件 → 场景 A:完整插件骨架
├── 为已有插件添加 Ribbon 界面 → 场景 B:UI 集成
├── 插件需要访问数据管理器 → 场景 C:数据访问
├── 插件需要工程存档(保存/加载) → 场景 D:工程存档
└── 插件需要调用 Python 脚本 → 参见 skill: python-script-integration

架构概览

┌────────────────── DAWorkbench 主程序 ──────────────────┐
│                                                         │
│  DAAppPluginManager                                     │
│    └ QPluginLoader::instance() 加载 bin/plugins/*.dll   │
│        ↓                                                │
│  DAAbstractNodePlugin (接口)                             │
│    ├ initialize()       ← 插件入口                       │
│    ├ createNodeFactory() ← 提供工作流节点(可返回 nullptr)│
│    ├ createSettingPage() ← 提供设置页(可返回 nullptr)   │
│    └ createArchiveTask() ← 提供存档任务                   │
│        ↓                                                │
│  DACoreInterface (核心接口)                              │
│    ├ getUiInterface()       → DAUIInterface              │
│    │    ├ getDockingArea()  → DADockingAreaInterface     │
│    │    ├ getRibbonArea()   → DARibbonAreaInterface      │
│    │    ├ getStatusBar()    → DAStatusBarInterface       │
│    │    └ getMainWindow()   → QMainWindow                │
│    ├ getDataManagerInterface() → DADataManagerInterface  │
│    ├ getProjectInterface()  → DAProjectInterface         │
│    └ getPythonSignalHandler() → DAPythonSignalHandler    │
└─────────────────────────────────────────────────────────┘

场景 A:完整插件骨架

A1. 目录结构
MyPlugin/
├── CMakeLists.txt           ← 顶层 CMake(定位 DAWorkbench 安装目录)
├── src/
│   ├── CMakeLists.txt       ← 插件 CMake(构建配置)
│   ├── MyPluginGlobal.h     ← 导出宏定义
│   ├── MyPlugin.h           ← 插件类声明
│   ├── MyPlugin.cpp         ← 插件类实现
│   ├── MyUI.h/.cpp          ← UI 管理类
│   ├── MyWorker.h/.cpp      ← 业务逻辑类
│   ├── my_resource.qrc      ← Qt 资源文件
│   └── PyScripts/           ← Python 脚本目录
│       └── MyPackage/
│           └── __init__.py
└── data-workbench/          ← 平台子模块(git submodule)
    └── bin_Release_qtX.Y.Z_MSVC_x64/  ← 构建安装后生成
A2. 顶层 CMakeLists.txt
cmake
cmake_minimum_required(VERSION 3.10)
project(MyPlugin DESCRIPTION "My Plugin For DAWorkbench")

# --- 定位 DAWorkbench 安装目录 ---
set(DA_MIN_QT_VERSION 5.14)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)

# 自动计算安装目录名: bin_<BuildType>_qt<QtVer>_<Compiler>_<Arch>
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
    set(_platform_name "x86")
else()
    set(_platform_name "x64")
endif()
set(DAWorkbench_INSTALL_FOLDER_NAME bin_${CMAKE_BUILD_TYPE}_qt${QT_VERSION}_${CMAKE_CXX_COMPILER_ID}_${_platform_name})
set(DAWorkbench_INSTALL_DIR "${CMAKE_CURRENT_LIST_DIR}/data-workbench/${DAWorkbench_INSTALL_FOLDER_NAME}")
set(DAWorkbench_DIR "${DAWorkbench_INSTALL_DIR}/lib/cmake/DAWorkbench")

# 加载平台提供的 CMake 宏
list(APPEND CMAKE_MODULE_PATH ${DAWorkbench_INSTALL_DIR})
list(APPEND CMAKE_MODULE_PATH ${DAWorkbench_DIR})
include(${DAWorkbench_DIR}/daworkbench_plugin_utils.cmake)

set(CMAKE_INSTALL_PREFIX ${DAWorkbench_INSTALL_DIR})

add_subdirectory(src)
A3. src/CMakeLists.txt
cmake
cmake_minimum_required(VERSION 3.10)

# --- 插件元信息宏(名称、描述、版本号、安装目录)---
damacro_plugin_setting(
    "MyPlugin"
    "My Plugin Description"
    0   # ver major
    1   # ver minor
    0   # ver patch
    ${DAWorkbench_INSTALL_DIR}
)

# --- Qt 依赖 ---
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} ${DA_MIN_QT_VERSION} COMPONENTS
    Core Gui Widgets Xml Svg PrintSupport Concurrent OpenGL
    REQUIRED
)
if(${QT_VERSION_MAJOR} EQUAL 6)
    find_package(Qt${QT_VERSION_MAJOR} COMPONENTS OpenGLWidgets Core5Compat REQUIRED)
endif()
if(WIN32)
    find_package(Qt${QT_VERSION_MAJOR} ${DA_MIN_QT_VERSION} COMPONENTS AxContainer REQUIRED)
endif()

# --- 文件加载 ---
file(GLOB DA_PLUGIN_HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
file(GLOB DA_PLUGIN_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
file(GLOB DA_PLUGIN_QT_UI_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.ui")
file(GLOB DA_PLUGIN_QT_RC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.qrc")

add_library(${DA_PLUGIN_NAME} SHARED
    ${DA_PLUGIN_HEADER_FILES}
    ${DA_PLUGIN_SOURCE_FILES}
    ${DA_PLUGIN_QT_UI_FILES}
    ${DA_PLUGIN_QT_RC_FILES}
)

target_compile_definitions(${DA_PLUGIN_NAME} PRIVATE MyPlugin_BUILDLIB)

# --- 第三方库导入(平台提供的宏) ---
damacro_import_SARibbonBar(${DA_PLUGIN_NAME} ${DAWorkbench_INSTALL_DIR})
damacro_import_DALiteCtk(${DA_PLUGIN_NAME} ${DAWorkbench_INSTALL_DIR})
damacro_import_QtAdvancedDocking(${DA_PLUGIN_NAME} ${DAWorkbench_INSTALL_DIR})
damacro_import_qwt(${DA_PLUGIN_NAME} ${DAWorkbench_INSTALL_DIR})
damacro_import_orderedmap(${DA_PLUGIN_NAME} ${DAWorkbench_INSTALL_DIR})
damacro_import_Python(${DA_PLUGIN_NAME} ${DAWorkbench_INSTALL_DIR})
damacro_import_pybind11(${DA_PLUGIN_NAME} ${DAWorkbench_INSTALL_DIR})

# --- DAWorkbench 组件依赖 ---
# 注意:DAWorkFlow 已废弃(用 DAPyWorkFlow),DACommonWidgets 已合并到 DAGui
find_package(DAWorkbench COMPONENTS
    DAUtils
    DAMessageHandler
    DAAxOfficeWrapper        # 仅 Windows 需要
    DAPyBindQt
    DAPyScripts
    DAData
    DAGraphicsView
    DAFigure
    DAPyCommonWidgets
    DAGui
    DAInterface
    DAPluginSupport
)

# DAWidgets 是独立第三方库(不是 DAWorkbench::DAWidgets),需显式 find_package
find_package(DAWidgets PATHS ${DAWorkbench_INSTALL_DIR})

target_link_libraries(${DA_PLUGIN_NAME} PUBLIC
    DAWorkbench::DAUtils
    DAWorkbench::DAMessageHandler
    DAWorkbench::DAAxOfficeWrapper
    DAWorkbench::DAPyBindQt
    DAWorkbench::DAPyScripts
    DAWorkbench::DAData
    DAWorkbench::DAGraphicsView
    DAWorkbench::DAFigure
    DAWorkbench::DAPyCommonWidgets
    DAWorkbench::DAGui
    DAWorkbench::DAInterface
    DAWorkbench::DAPluginSupport
    Qt${QT_VERSION_MAJOR}::Core
    Qt${QT_VERSION_MAJOR}::Gui
    Qt${QT_VERSION_MAJOR}::Widgets
    Qt${QT_VERSION_MAJOR}::Xml
    Qt${QT_VERSION_MAJOR}::Svg
    Qt${QT_VERSION_MAJOR}::PrintSupport
)

# --- 构建属性 ---
set_target_properties(${DA_PLUGIN_NAME} PROPERTIES
    AUTOMOC ON
    AUTOUIC ON
    AUTORCC ON
    CXX_EXTENSIONS OFF
    DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}
    VERSION ${DA_PLUGIN_VERSION}
    EXPORT_NAME ${DA_PLUGIN_NAME}
    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    # DLL 直接输出到平台的 plugins 目录
    RUNTIME_OUTPUT_DIRECTORY "${DAWorkbench_INSTALL_DIR}/bin/plugins"
)

# --- 安装 ---
damacro_plugin_install()

# --- Python 脚本复制(配置阶段自动执行)---
file(COPY "${CMAKE_CURRENT_LIST_DIR}/PyScripts/MyPackage"
     DESTINATION ${DAWorkbench_INSTALL_DIR}/bin/PyScripts)
install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/PyScripts/MyPackage"
        DESTINATION ${CMAKE_INSTALL_BINDIR}/PyScripts)
A4. 导出宏头文件
cpp
// MyPluginGlobal.h
#ifndef MYPLUGIN_GLOBAL_H
#define MYPLUGIN_GLOBAL_H
#include <QtCore/QtGlobal>
#if defined(MYPLUGIN_BUILDLIB)
#define MYPLUGIN_API Q_DECL_EXPORT
#else
#define MYPLUGIN_API Q_DECL_IMPORT
#endif
#endif
A5. 插件类
cpp
// MyPlugin.h
#include <QObject>
#include "DAAbstractNodePlugin.h"
#include "DAAbstractSettingPage.h"
#include "DAAbstractArchiveTask.h"

class MyUI;
class MyWorker;

class MyPlugin : public QObject, public DA::DAAbstractNodePlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID DAABSTRACTNODEPLUGIN_IID)
    Q_INTERFACES(DA::DAAbstractNodePlugin)
public:
    MyPlugin();
    ~MyPlugin() override;

    // === 必须实现的纯虚函数 ===
    bool initialize() override;
    QString getIID() const override;
    QString getName() const override;
    QString getVersion() const override;
    QString getDescription() const override;

    // === 节点工厂(如不提供自定义节点,返回 nullptr)===
    DA::DAPyNodeFactory* createNodeFactory() override;
    void destroyNodeFactory(DA::DAPyNodeFactory* p) override;

    // === 可选重写 ===
    DA::DAAbstractSettingPage* createSettingPage() override;
    std::shared_ptr<DA::DAAbstractArchiveTask> createArchiveTask(bool isSave) override;

private:
    MyUI* mUI { nullptr };
    MyWorker* mWorker { nullptr };
};
cpp
// MyPlugin.cpp
#include "MyPlugin.h"
#include "MyUI.h"
#include "MyWorker.h"
#include "DAZipArchiveTask_Xml.h"
#include "DALog.h"

MyPlugin::MyPlugin() : DA::DAAbstractNodePlugin() {}
MyPlugin::~MyPlugin() {}

bool MyPlugin::initialize()
{
    // 1. 初始化 UI
    mUI = new MyUI(this);
    mUI->initialize(core());  // core() 来自 DAAbstractPlugin 基类

    // 2. 初始化业务逻辑
    mWorker = new MyWorker(this);
    mWorker->initialize(core(), mUI);

    // 3. 连接 UI 和 Worker
    mUI->bindWorker(mWorker);

    // 4. 初始化 Python 环境(如有)
    if (!mWorker->initializePythonEnv()) {
        daCritical << QString(u8"初始化 Python 脚本失败");
    }

    // 5. 调用基类 initialize
    return DA::DAAbstractNodePlugin::initialize();
}

QString MyPlugin::getIID() const { return "Plugin.MyPlugin"; }
QString MyPlugin::getName() const { return u8"My Plugin"; }
QString MyPlugin::getVersion() const { return "1.0.0"; }
QString MyPlugin::getDescription() const { return u8"插件描述"; }

DA::DAPyNodeFactory* MyPlugin::createNodeFactory()
{
    // 不提供工作流节点时返回 nullptr
    return nullptr;
}

void MyPlugin::destroyNodeFactory(DA::DAPyNodeFactory* p)
{
    delete p;  // DAPyNodeFactory 继承自 DAPyObjectWrapper(非 QObject),直接 delete
}

DA::DAAbstractSettingPage* MyPlugin::createSettingPage()
{
    return nullptr;  // 无设置页
}

// === 工程存档 ===
static const char* cs_xmlFilePath = "myplugin/data.xml";

std::shared_ptr<DA::DAAbstractArchiveTask> MyPlugin::createArchiveTask(bool isSave)
{
    if (isSave) {
        QDomDocument doc;
        doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""));
        QDomElement root = doc.createElement("root");
        doc.appendChild(root);
        mWorker->saveToXml(root, doc);
        mUI->saveToXml(root, doc);
        return std::make_shared<DA::DAZipArchiveTask_Xml>(cs_xmlFilePath, doc);
    } else {
        auto task = std::make_shared<DA::DAZipArchiveTask_Xml>(cs_xmlFilePath);
        task->setLoadedCallBack([this](std::shared_ptr<DA::DAAbstractArchiveTask> t) {
            auto xmltask = std::static_pointer_cast<DA::DAZipArchiveTask_Xml>(t);
            QDomDocument doc = xmltask->getDomDocument();
            QDomElement root = doc.firstChildElement("root");
            if (!root.isNull()) {
                mWorker->loadFromXml(root);
                mUI->loadFromXml(root);
            }
        });
        return task;
    }
}
A6. 推荐的 UI/Worker 分层模式

DAWorkbench 插件推荐将代码分为 UI 层和业务层:

MyPlugin (入口)
  ├── MyUI (UI 层)
  │     ├── 管理 Ribbon 面板、Action、Dock 窗口
  │     ├── 转发用户操作到 Worker
  │     └── 从 Worker 接收数据更新界面
  └── MyWorker (业务层)
        ├── 数据处理逻辑
        ├── Python 脚本调用
        └── 绘图模板管理

UI 层不直接处理数据,Worker 层不直接操作界面。两者通过信号槽通信。

cpp
// MyUI.h
#include <QObject>
#include "DAData.h"

namespace DA { class DACoreInterface; class DAUIInterface; }
class MyWorker;

class MyUI : public QObject
{
    Q_OBJECT
public:
    explicit MyUI(QObject* par = nullptr);
    void initialize(DA::DACoreInterface* core);
    void bindWorker(MyWorker* worker);
    void saveToXml(QDomElement& parentElement, QDomDocument& doc);
    void loadFromXml(const QDomElement& parentElement);
private:
    DA::DACoreInterface* m_core { nullptr };
    DA::DAUIInterface* m_ui { nullptr };
    QMainWindow* m_mainWindow { nullptr };
    MyWorker* m_worker { nullptr };
    QAction* actionMyAction { nullptr };
    // ... 其他 UI 成员
};

场景 B:UI 集成

B1. 获取 UI 接口
cpp
void MyUI::initialize(DA::DACoreInterface* core)
{
    m_core = core;
    m_ui = core->getUiInterface();
    m_mainWindow = m_ui->getMainWindow();

    // 获取各 UI 区域
    DA::DADockingAreaInterface* dockArea = m_ui->getDockingArea();
    DA::DARibbonAreaInterface* ribbonArea = m_ui->getRibbonArea();
    DA::DAActionsInterface* actionInterface = m_ui->getActionInterface();
    DA::DAStatusBarInterface* statusBar = m_ui->getStatusBar();
}
B2. 添加 Ribbon 工具栏
cpp
#include "SARibbonBar.h"
#include "SARibbonCategory.h"
#include "SARibbonPanel.h"

void MyUI::initialize(DA::DACoreInterface* core)
{
    // ... 获取接口 ...

    SARibbonBar* ribbon = ribbonArea->ribbonBar();

    // 方式1:在已有主页面板中添加 Action
    SARibbonPanel* dataOptPanel = ribbonArea->getPannelByObjectName(
        QStringLiteral("da-pannel-main.data-opt"));
    if (dataOptPanel) {
        actionMyAction = new QAction(QIcon(":/myicon.svg"), QString(u8"我的功能"));
        dataOptPanel->addLargeAction(actionMyAction);
    }

    // 方式2:创建新的 Ribbon 标签页
    SARibbonCategory* myCategory = new SARibbonCategory(QString(u8"我的功能"), ribbon);
    ribbon->addCategoryPage(myCategory);

    SARibbonPanel* panel1 = myCategory->addPanel(QString(u8"操作"));
    QAction* action1 = new QAction(QIcon(":/icon1.svg"), QString(u8"操作1"));
    panel1->addLargeAction(action1);

    // 添加可选中的 Action(如设备选择)
    QAction* actionSelectable = new QAction(this);
    actionSelectable->setCheckable(true);
    actionSelectable->setChecked(true);
    panel1->addLargeAction(actionSelectable);
}
B3. 隐藏不需要的 UI 元素
cpp
void MyUI::initialize(DA::DACoreInterface* core)
{
    DA::DADockingAreaInterface* dockArea = m_ui->getDockingArea();
    DA::DARibbonAreaInterface* ribbonArea = m_ui->getRibbonArea();
    DA::DAActionsInterface* actionInterface = m_ui->getActionInterface();

    // 隐藏不需要的 Dock 窗口(如工作流相关)
    dockArea->hideDockWidget(dockArea->getWorkFlowOperateWidget());
    dockArea->hideDockWidget(dockArea->getWorkflowNodeListWidget());

    // 隐藏不需要的 Ribbon 面板
    SARibbonPanel* panel = ribbonArea->getPannelByObjectName("da-pannel-main.workflow");
    if (panel) panel->hide();

    // 隐藏不需要的 Action
    if (QAction* a = actionInterface->findAction("actionShowWorkFlowArea")) {
        a->setVisible(false);
    }
}
B4. 创建 Dock 停靠窗口
cpp
#include "DockWidget.h"
#include "DockManager.h"

void MyUI::initialize(DA::DACoreInterface* core)
{
    DA::DADockingAreaInterface* dockArea = m_ui->getDockingArea();

    // 方式1:在中心停靠区创建标签页式 Dock
    QWidget* myWidget = new QWidget();
    ads::CDockWidget* myDock = dockArea->createDockWidgetTabAtCenterDockArea(
        myWidget, QString(u8"我的窗口"));

    // 方式2:作为已有 Dock 的标签页
    ads::CDockWidget* settingDock = dockArea->getSettingContainerDock();
    ads::CDockWidget* myTabDock = dockArea->createDockWidgetAsTab(
        myWidget, QStringLiteral("my_widget_dock"),
        settingDock->dockAreaWidget());
    myTabDock->setWindowTitle(QString::fromUtf8("我的标签页"));

    // 切换到特定功能区域
    dockArea->raiseFeatureArea(DA::DAWorkbenchFeatureType::Chart);
}
cpp
#include "SARibbonGallery.h"
#include "SARibbonGalleryGroup.h"

void MyUI::buildTemplateGallery()
{
    SARibbonPanel* panel = m_category->addPanel(QString(u8"模板"));
    SARibbonGallery* gallery = panel->addGallery();

    QList<QAction*> actions;
    for (const auto& tmpl : m_templates) {
        QAction* act = new QAction(QIcon(":/icon.svg"), tmpl->name(), this);
        act->setData(QVariant::fromValue(tmpl));
        actions.append(act);
    }

    SARibbonGalleryGroup* group = gallery->addCategoryActions(
        QString(u8"模板组"), actions);
    group->setGalleryGroupStyle(SARibbonGalleryGroup::IconWithWordWrapText);
    group->setGridMinimumWidth(80);

    connect(group, &SARibbonGalleryGroup::triggered,
            this, &MyUI::onTemplateSelected);
}
B6. 状态栏交互
cpp
void MyWorker::doLongTask()
{
    DA::DAStatusBarInterface* statusBar = m_ui->getStatusBar();
    statusBar->showProgressBar();
    statusBar->setBusy(true);
    statusBar->setProgressText(QString(u8"正在处理..."));
    statusBar->setProgress(50.0);

    // ... 处理逻辑 ...

    statusBar->hideProgressBar();
    statusBar->setBusy(false);
    statusBar->showMessage(QString(u8"完成!"));
}

场景 C:数据访问

C1. 通过 DataManager 查找数据
cpp
#include "DADataManagerInterface.h"
#include "DAData.h"

void MyWorker::loadData()
{
    DA::DADataManagerInterface* datamgr = m_core->getDataManagerInterface();

    // 按名称通配符查找数据表
    QList<DA::DAData> moduleDatas = datamgr->findDatas("*module*");
    QList<DA::DAData> indoorDatas = datamgr->findDatas("*indoor*");
    QList<DA::DAData> systemDatas = datamgr->findDatas("*system*");

    // 遍历数据
    for (const DA::DAData& d : moduleDatas) {
        QString name = d.getName();
        // 从名称提取信息
        auto parts = name.split("_");
        int ip = parts.last().toInt();
        // ...
    }
}
C2. DAData 转 DataFrame
cpp
#include "DAPyDataFrame.h"

void MyWorker::processData(const DA::DAData& data)
{
    // DAData 转 DataFrame(Python pandas 对象)
    DA::DAPyDataFrame df = data.toDataFrame();
    auto shape = df.shape();
    int rows = static_cast<int>(shape.first);
    int cols = static_cast<int>(shape.second);

    // 逐列读取数据
    QVector<double> values;
    df[0].castTo<double>(std::back_inserter(values));
}
C3. 创建绘图(Figure)
cpp
#include "DAChartOperateWidget.h"
#include "DAFigureWidget.h"
#include "DAChartManageWidget.h"
#include "DADockingAreaInterface.h"

bool MyWorker::createFigure(const QString& name)
{
    DA::DADockingAreaInterface* docking = m_ui->getDockingArea();
    DA::DAChartOperateWidget* chartOpt = docking->getChartOperateWidget();

    // 创建 Figure
    DA::DAFigureWidget* figureWidget = chartOpt->createFigure(name);

    // 获取 Figure 管理器
    QwtFigure* figure = figureWidget->figure();

    // 获取所有 Plot
    QList<QwtPlot*> plots = figure->allAxes();

    // 配置绘图...
    for (QwtPlot* plot : plots) {
        plot->rescaleAxes();
    }

    // 显示 Dock
    m_ui->getDockingArea()->raiseDockByWidget(chartOpt);
    return true;
}

场景 D:工程存档

D1. 保存到 XML
cpp
void MyWorker::saveToXml(QDomElement& parentElement, QDomDocument& doc)
{
    QDomElement workerElement = doc.createElement("worker");
    parentElement.appendChild(workerElement);

    // 保存状态
    workerElement.setAttribute("value", QString::number(m_someValue));

    // 保存列表
    for (int i : m_someList) {
        QDomElement item = doc.createElement("item");
        item.setAttribute("ip", QString::number(i));
        workerElement.appendChild(item);
    }
}
D2. 从 XML 加载
cpp
bool MyWorker::loadFromXml(const QDomElement& parentElement)
{
    QDomElement workerElement = parentElement.firstChildElement("worker");
    if (workerElement.isNull()) return false;

    m_someValue = workerElement.attribute("value").toInt();

    m_someList.clear();
    for (QDomElement item = workerElement.firstChildElement("item");
         !item.isNull();
         item = item.nextSiblingElement("item")) {
        m_someList.append(item.attribute("ip").toInt());
    }
    return true;
}
D3. 存档机制说明

createArchiveTask(isSave) 返回 DAAbstractArchiveTask 的子类。常用 DAZipArchiveTask_Xml:

  • 保存:传入 XML 路径和 QDomDocument,框架将其写入工程压缩包
  • 加载:传入 XML 路径,框架从工程压缩包读取,通过 setLoadedCallBack 回调通知

关键接口速查

接口获取方式用途
DACoreInterfacecore() (基类提供)核心入口,获取所有其他接口
DAUIInterfacecore()->getUiInterface()界面接口
DADockingAreaInterfaceui->getDockingArea()停靠窗口管理
DARibbonAreaInterfaceui->getRibbonArea()Ribbon 工具栏管理
DAStatusBarInterfaceui->getStatusBar()状态栏管理
DAActionsInterfaceui->getActionInterface()Action 管理
DADataManagerInterfacecore()->getDataManagerInterface()数据管理
DAProjectInterfacecore()->getProjectInterface()工程管理
DAPythonSignalHandlercore()->getPythonSignalHandler()Python 跨线程通信

DAWorkbench 组件速查

组件用途
DAUtils通用工具函数
DAMessageHandler全局消息处理
DAAxOfficeWrapperOffice COM 自动化(仅 Windows)
DAPyBindQtpybind11 与 Qt 集成
DAPyScriptsPython 脚本资源管理
DAData数据模型管理
DAGraphicsView图形视图框架
DAFigure科学绘图(基于 qwt)
DAPyCommonWidgetsPython 相关窗口部件
DAGui主界面 GUI 组件
DAInterface接口层
DAPluginSupport插件加载支持

已废弃:DAWorkFlow → 用 DAPyWorkFlow;DACommonWidgets → 已合并到 DAGui。

第三方库导入宏

宏导入库
damacro_import_SARibbonBarSARibbonBar(Ribbon 工具栏)
damacro_import_DALiteCtkDALiteCtk
damacro_import_QtAdvancedDockingADS(停靠面板)
damacro_import_qwtQwt(科学绘图)
damacro_import_orderedmaptsl::ordered_map
damacro_import_PythonPython3 开发库
damacro_import_pybind11pybind11 头文件
damacro_import_spdlogspdlog(日志)

常见陷阱

  1. 必须先构建 data-workbench 子模块 — 插件依赖 daworkbench_plugin_utils.cmake 和所有 DAWorkbench 库
  2. 使用 Visual Studio 生成器 — 不要用 Ninja,PowerShell 中 MSVC 环境无法正确注入
  3. 构建类型必须一致 — 插件的 --config 参数必须与 data-workbench 一致(Release/Debug)
  4. DAWidgets 需显式 find_package — DAGui 依赖 DAWidgets,但 DAWorkbenchConfig 不会自动加载它
  5. Q_PLUGIN_METADATA 必须正确 — IID 必须是 DAABSTRACTNODEPLUGIN_IID
  6. 插件类必须同时继承 QObject 和 DAAbstractNodePlugin — QObject 必须是第一个基类
  7. DLL 直接输出到 plugins 目录 — 通过 RUNTIME_OUTPUT_DIRECTORY 设置,非 install 阶段
  8. Python 脚本通过 file(COPY) 部署 — CMake 配置阶段自动复制到 bin/PyScripts/,修改 .py 后需重新 CMake configure 或手动复制

参考文件

文件说明
src/MyPlugin.h/.cpp完整插件实现示例
src/MyUI.h/.cppUI 管理类示例(Ribbon/Dock/Action)
src/MyWorker.h/.cpp业务逻辑类示例(数据/绘图/Python)
src/CMakeLists.txt插件 CMake 完整配置
data-workbench/cmake/daworkbench_plugin_utils.cmake平台 CMake 宏定义
data-workbench/src/DAPluginSupport/DAAbstractNodePlugin.h插件接口定义
data-workbench/src/DAPluginSupport/DAAbstractPlugin.h插件基类定义
data-workbench/src/DAInterface/DACoreInterface.h核心接口定义
data-workbench/src/DAInterface/DAUIInterface.hUI 接口定义

© czyt1988, LGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in skills/create-cpp-plugin of czyt1988/data-workbench.

Open the folder on GitHubat commit cf3bbda

Compare with similar skills

Create Cpp Plugin next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Create Cpp Plugin compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Create Cpp Plugin this skillczyt1988/data-workbench102—~5.5kAutomated safety check: PassLGPL-3.0
Smooth Cpp Sharedopenforecast-org/smooth107—~1.1kAutomated safety check: PassLGPL-2.1
Optimize Op VerifyCVCUDA/CV-CUDA2.7k—~424Automated safety check: PassCustom licence
Elodin DBelodin-sys/elodin547—~2.8kAutomated safety check: PassApache-2.0
GeomasterLeonChaoX/qinyan-academic-skills9371 repos~2.9kAutomated safety check: PassMIT
Geomasteragent-skills-hub/agent-skills-hub1111 repos~5.2kAutomated safety check: PassMIT

Similar skills

  • Smooth Cpp Shared

    openforecast-org/smooth

    Work on the C++ layer that the R package and the Python port share — the headers under src/headers/, the Rcpp bindings in src/, the pybind11 bindings in src/python/, and the two build systems that…

    107 GitHub stars~1.1k tokensUpdated yesterday
    Data & AnalyticsAuto-check passed
  • Optimize Op Verify

    CVCUDA/CV-CUDA

    Verify a CV-CUDA optimization campaign's deterministic definition-of-done and concise versioned MR summary per .agents/guidance/OPTIMIZATIONGUIDELINES.md.

    2.7k GitHub stars~424 tokensUpdated 21 days ago
    Data & AnalyticsAuto-check passed
  • Elodin DB

    elodin-sys/elodin

    Work with Elodin-DB, the time-series telemetry database. An agent skill from elodin-sys/elodin.

    547 GitHub stars~2.8k tokensUpdated today
    Data & AnalyticsAuto-check passed
  • Geomaster

    LeonChaoX/qinyan-academic-skills

    Comprehensive geospatial science skill covering remote sensing, GIS, spatial analysis, machine learning for earth observation, and 30+ scientific domains.

    937 GitHub starsUsed in 1 repo~2.9k tokens
    Data & AnalyticsAuto-check passed
  • Geomaster

    agent-skills-hub/agent-skills-hub

    Comprehensive geospatial science skill covering remote sensing, GIS, spatial analysis, machine learning for earth observation, and 30+ scientific domains.

    111 GitHub starsUsed in 1 repo~5.2k tokens
    Data & AnalyticsAuto-check passed
  • Geomaster

    K-Dense-AI/scientific-agent-skills

    Supports geospatial research workflows for remote sensing, vector and raster GIS, spatial statistics, terrain and network analysis, and machine learning for Earth observation.

    48k GitHub starsUsed in 1 repo~2.8k tokens
    Data & AnalyticsAuto-check passed

More from czyt1988/data-workbench

  • Add Python Binding

    czyt1988/data-workbench

    A skill your agent uses when adding new Python bindings (exposing C++ classes/functions to Python) in the DAWorkBench project, or modifying existing bindings.

    102 GitHub stars~4.6k tokensUpdated 25 days ago
    Auto-check passed
  • Create Setting Panel

    czyt1988/data-workbench

    A skill your agent uses when creating property panels or configuration UI in the data-workbench Qt/C++ project.

    102 GitHub stars~3.2k tokensUpdated 25 days ago
    Auto-check passed
  • Python Script Integration

    czyt1988/data-workbench

    A skill your agent uses when integrating Python scripts with C++ in a DAWorkbench plugin — calling Python from C++, Python multithreading without UI conflicts, Python-to-C++ data exchange, Python UI…

    102 GitHub stars~5.5k tokensUpdated 25 days ago
    Auto-check passed

Works with

Questions about Create Cpp Plugin

What does Create Cpp Plugin do?

A skill your agent uses when creating a new C++ plugin DLL for the data-workbench platform, or modifying an existing plugin's structure, CMake, UI integration, or data access. Create Cpp Plugin is an agent skill from czyt1988/data-workbench. Use when creating a new C++ plugin DLL for the data-workbench platform, or modifying an existing plugin's structure, CMake, UI integration, or data access.

When should I use Create Cpp Plugin?

Create Cpp Plugin fits situations like: creating a new C++ plugin DLL for the data-workbench platform; modifying an existing plugins structure.

How do I install Create Cpp Plugin in Claude Code?

Run `npx skills add czyt1988/data-workbench --skill create-cpp-plugin -a claude-code`. Or copy the skill folder (skills/create-cpp-plugin in czyt1988/data-workbench) into .claude/skills/create-cpp-plugin in your project. Claude Code loads it when a task matches its description.

How do I install Create Cpp Plugin in Codex?

Run `npx skills add czyt1988/data-workbench --skill create-cpp-plugin -a codex`. Or copy the skill folder (skills/create-cpp-plugin in czyt1988/data-workbench) into .agents/skills/create-cpp-plugin in your project. Codex loads it when a task matches its description.

Can I use Create Cpp Plugin in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add czyt1988/data-workbench --skill create-cpp-plugin -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/create-cpp-plugin, .gemini/skills/create-cpp-plugin, .github/skills/create-cpp-plugin and .opencode/skills/create-cpp-plugin in your project.

What does Create Cpp Plugin need to run?

SKILL.md names no scripts, command-line tools or credentials: Create Cpp Plugin is instructions for the agent only. Our summary lists: Python 3.

Does Create Cpp Plugin access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Create Cpp Plugin safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Create Cpp Plugin use?

Create Cpp Plugin is published under the LGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Create Cpp Plugin use?

About 5.5k tokens (SKILL.md is roughly 22k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Create Cpp Plugin?

Skills that share tags, products or a category with Create Cpp Plugin: Smooth Cpp Shared (openforecast-org/smooth, 107 stars), Optimize Op Verify (CVCUDA/CV-CUDA, 2.7k stars), Elodin DB (elodin-sys/elodin, 547 stars) and Geomaster (LeonChaoX/qinyan-academic-skills, 937 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Create Cpp Plugin?

czyt1988 (a GitHub user) maintains it in czyt1988/data-workbench, which has 102 GitHub stars. The repository holds 4 skills in this directory. The repository was last updated on September 12, 2026.

Source: czyt1988/data-workbench on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.