QT CREATOR 插件开发:添加新的工程类型(下)

2023-11-05

Core::BaseFileWizard

类Core::BaseFileWizard在
coreplugin/basefilewizard.h 文件中声明:

class CORE_EXPORT BaseFileWizard : public IWizard
{
    Q_DISABLE_COPY(BaseFileWizard)
    Q_OBJECT

public:
    virtual ~BaseFileWizard();

    // IWizard
    virtual WizardKind kind() const;
    virtual QIcon icon() const;
    virtual QString description() const;
    virtual QString displayName() const;
    virtual QString id() const;

    virtual QString category() const;
    virtual QString displayCategory() const;

    virtual void runWizard(const QString &path, QWidget *parent);

    // Build a file name, adding the extension unless baseName already has one
    static QString buildFileName(const QString &path,
                                 const QString &baseName,
                                 const QString &extension);

    // Sets some standard options on a QWizard
    static void setupWizard(QWizard *);

    // Read "shortTitle" dynamic property of the pageId
    // and apply it as the title of corresponding progress item
    static void applyExtensionPageShortTitle(Utils::Wizard *wizard, int pageId);

protected:
    typedef QList WizardPageList;

    explicit BaseFileWizard(const BaseFileWizardParameters ¶meters,
                            QObject *parent = 0);

    // Overwrite to create the wizard dialog on the parent, adding
    // the extension pages.
    virtual QWizard *createWizardDialog(QWidget *parent,
                                    const QString &defaultPath,
                                    const WizardPageList &extensionPages) const = 0;

    // Overwrite to query the parameters from the dialog and generate the files.
    virtual GeneratedFiles generateFiles(const QWizard *w,
                                         QString *errorMessage) const = 0;

    /* Physically write files. Re-implement (calling the base implementation)
     * to create files with CustomGeneratorAttribute set. */
    virtual bool writeFiles(const GeneratedFiles &files, QString *errorMessage);

    /* Overwrite to perform steps to be done after files are actually created.
     * The default implementation opens editors with the newly generated files. */
    virtual bool postGenerateFiles(const QWizard *w,
                                   const GeneratedFiles &l,
                                   QString *errorMessage);

    // Utility that returns the preferred suffix for a mime type
    static QString preferredSuffix(const QString &mimeType);

    // Utility that performs an overwrite check on a set of files. It checks if
    // the file exists, can be overwritten at all and prompts the user.
    enum OverwriteResult { OverwriteOk,  OverwriteError,  OverwriteCanceled };
    OverwriteResult promptOverwrite(const QStringList &files,
                                    QString *errorMessage) const;

    // Utility to open the editors for the files whose attribute is set accordingly.
    static bool postGenerateOpenEditors(const GeneratedFiles &l,
                                        QString *errorMessage = 0);

private:
    BaseFileWizardPrivate *m_d;
};

BaseFileWizard类实现了IWizard接口,并且增加了几个新的函数:

  • createWizardDialog– 该函数必须被子类重写,用于提供一个供runWizard()函数显示的向导,其中parent参数应当作为该函数返回的QWizard的父类defaultPath参数应当作为生成的文件的默认路径extensionPages参数列出了应该被向导默认显示的所有页面
  • generateFiles– 该函数在用户点击了向导的“完成”按钮之后自动调用,该函数的实现必须按要求创建Core::GeneratedFile类的实例
  • postGenerateFiles– 该函数在generateFiles()返回之后被调用,子类可以通过覆盖该函数,做你需要做的任何事情

下面,我们使用BaseFileWizard来实现我们自己的向导:

#ifndef MODELCLASSWIZARD_H
#define MODELCLASSWIZARD_H

#include <coreplugin/basefilewizard.h>
#include <QMap>

class ModelClassWizard : public Core::BaseFileWizard
{
    Q_OBJECT
public:
    ModelClassWizard(const Core::BaseFileWizardParameters ¶meters,
                     QObject *parent = 0);
    ~ModelClassWizard();
    QWizard *createWizardDialog(QWidget *parent,
                                const QString &defaultPath,
                                const WizardPageList &extensionPages) const;
    Core::GeneratedFiles generateFiles(const QWizard *w,
                                       QString *errorMessage) const;
private:
    QString readFile(const QString& fileName,
                     const QMap& replacementMap) const;
};

#endif // MODELCLASSWIZARD_H

我们的构造函数和析构函数很简单:

ModelClassWizard::ModelClassWizard(const Core::BaseFileWizardParameters ¶meters,
                                   QObject *parent)
    : Core::BaseFileWizard(parameters, parent)
{
}

ModelClassWizard::~ModelClassWizard()
{
}

函数createWizardDialog()创建一个很简单的QWizard,将我们前面写好的ModelNamePage作为其第一个页面,后面则添加其他默认页面:

QWizard* ModelClassWizard::createWizardDialog(QWidget *parent,
                                              const QString &defaultPath,
                                              const WizardPageList &extensionPages) const
{
    // Create a wizard
    QWizard* wizard = new QWizard(parent);
    wizard->setWindowTitle("Model Class Wizard");
    // Make our page as first page
    ModelNamePage* page = new ModelNamePage(wizard);
    int pageId = wizard->addPage(page);
    wizard->setProperty("_PageId_", pageId);
    page->setPath(defaultPath);
    // Now add the remaining pages
    foreach (QWizardPage *p, extensionPages) {
        wizard->addPage(p);
    }
    return wizard;
}

函数readFile()读取文件,将其内容以字符串的形式返回。在返回字符串之前,函数需要使用第二个参数提供的替换字符表修正这个字符串:

QString ModelClassWizard::readFile(const QString& fileName,
                                   const QMap& replacementMap) const
{
    QFile file(fileName);
    file.open(QFile::ReadOnly);
    QString retStr = file.readAll();
    QMap::const_iterator it = replacementMap.begin();
    QMap::const_iterator end = replacementMap.end();
    while(it != end) {
        retStr.replace(it.key(), it.value());
        ++it;
    }
    return retStr;
}

【领QT开发教程学习资料,点击下方链接莬费领取↓↓,先码住不迷路~】

点击这里:Qt资料领取(视频教程+文档+代码+项目实战)

这个函数将会实现这么一个功能:假设我们有一个文件 sample.txt:

#ifndef {{UPPER_CLASS_NAME}}_H
#define {{UPPER_CLASS_NAME}}_H

#include <{{BASE_CLASS_NAME}}>

struct {{CLASS_NAME}}Data;

class {{CLASS_NAME}} : public {{BASE_CLASS_NAME}}
{
    Q_OBJECT

public:
    {{CLASS_NAME}}(QObject* parent=0);
    ~{{CLASS_NAME}}();

    int rowCount(const QModelIndex& parent) const;
    QVariant data(const QModelIndex& index, int role) const;

private:
    {{CLASS_NAME}}Data* d;
};

#endif // {{UPPER_CLASS_NAME}}_H

其中的 {{xyz}} 作为一种占位符。如果我们有如下代码片段:

QMap replacementMap;
replacementMap["{{UPPER_CLASS_NAME}}"] = "LIST_MODEL";
replacementMap["{{BASE_CLASS_NAME}}"] = "QAbstractListModel";
replacementMap["{{CLASS_NAME}}"] = "ListModel";

QString contents = readFile("Sample.txt", replacementTable);

那么,执行过后 contents 字符串的内容应该是:

#ifndef LIST_MODEL_H
#define LIST_MODEL_H

#include <QAbstractListModel>

struct ListModelData;

class ListModel : public QAbstractListModel
{
    Q_OBJECT

public:
    ListModel(QObject* parent=0);
    ~ListModel();

    int rowCount(const QModelIndex& parent) const;
    QVariant data(const QModelIndex& index, int role) const;

private:
    ListModelData* d;
};

#endif // LIST_MODEL_H

看起来很神奇吗?我们的实际策略与此类似:提供这种模板文件,然后使用用户输入的信息替换其中的占位符,来生成相应的文件。

下面,我们来看看函数generateFiles()的实现。这个函数创建了两个Core::GeneratedFile对象,并且在返回之前赋予了正确的数据:

Core::GeneratedFiles ModelClassWizard::generateFiles(const QWizard *w,
                                                     QString *errorMessage) const
{
    Q_UNUSED(errorMessage);
    Core::GeneratedFiles ret;
    int pageId = w->property("_PageId_").toInt();
    ModelNamePage* page = qobject_cast(w->page(pageId));
    if(!page) {
        return ret;
    }
    ModelClassParameters params = page->parameters();
    QMap replacementMap;
    replacementMap["{{UPPER_CLASS_NAME}}"] = params.className.toUpper();
    replacementMap["{{BASE_CLASS_NAME}}"] = params.baseClass;
    replacementMap["{{CLASS_NAME}}"] = params.className;
    replacementMap["{{CLASS_HEADER}}"] = QFileInfo(params.headerFile).fileName();
    Core::GeneratedFile headerFile(params.path + "/" + params.headerFile);
    headerFile.setEditorId(CppEditor::Constants::CPPEDITOR_ID);
    Core::GeneratedFile sourceFile(params.path + "/" + params.sourceFile);
    sourceFile.setEditorId(CppEditor::Constants::CPPEDITOR_ID);
    if(params.baseClass == "QAbstractItemModel") {
        headerFile.setContents(readFile(":/ModelClassWizard/ItemModelHeader",
                                        replacementMap));
        sourceFile.setContents(readFile(":/ModelClassWizard/ItemModelSource",
                                        replacementMap));
    } else if(params.baseClass == "QAbstractTableModel") {
        headerFile.setContents(readFile(":/ModelClassWizard/TableModelHeader",
                                        replacementMap));
        sourceFile.setContents(readFile(":/ModelClassWizard/TableModelSource",
                                        replacementMap));
    } else if(params.baseClass == "QAbstractListModel") {
        headerFile.setContents(readFile(":/ModelClassWizard/ListModelHeader",
                                        replacementMap));
        sourceFile.setContents(readFile(":/ModelClassWizard/ListModelSource",
                                        replacementMap));
    }
    ret << headerFile << sourceFile;
    return ret;
}

实现插件

同前面一样,我们的插件实现类也只是替换掉initialize()函数的内容:

bool CustomProjectWizardPlugin::initialize(const QStringList& args, QString *errMsg)
{
    Q_UNUSED(args);
    Q_UNUSED(errMsg);

    Core::BaseFileWizardParameters params;
    params.setKind(Core::IWizard::ClassWizard);
    params.setIcon(qApp->windowIcon());
    params.setDescription("Generates an item-model class");
    params.setDisplayName("Item Model");
    params.setCategory("GalaxyWorld");
    params.setDisplayCategory(tr("GalaxyWorld"));

    addAutoReleasedObject(new ModelClassWizard(params, this));

    return true;
}

最后来测试一下我们的插件。

因为我们的向导是文件类型的,所以需要首先打开一个工程:

Open Project for Test

然后在工程名字上面点右键,添加新文件,可以看到我们的插件提供的文件类型:

Add Item Model New File

点击下方的“选择...”按钮,弹出我们设计的用户输入界面,填入 MyItemModel,可以看到下面的 Header 和 Implementation 都会自动修改:

Input Item Model Data

点击“下一步”,看看新的界面。这个页面就是系统默认添加的,还记得我们写的函数中最后那个循环吗?注意默认路径,Qt Creator 已经帮我们写好了:

Add Files to Project

点击完成,就可以看到,我们的文件已经生成好了!

结语

这是我们 《Qt Creator 插件开发》的最后一个章节。从我们以往的内容可以看出,Qt Creator 的插件开发并不是那么高不可攀,唯一的问题在于文档:Qt Creator 插件开发的文档一直写的不清不楚。虽然最新版本已经改善了很多,但是就学习而言,还是远远不够的。希望本文也能起到抛砖引玉的作用,最好能够让大家一起加入到 Qt Creator 的开发活动中来,一起完善这个 IDE。

感谢大家一直以来的支持!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT CREATOR 插件开发:添加新的工程类型(下) 的相关文章

  • 如何使用C从http下载文件?

    最近几天我试图弄清楚如何从 URL 下载文件 这是我对套接字的第一个挑战 我用它来了解协议 所以我想在没有 cURL 库的情况下只用 C 语言来完成它 我搜索了很多 现在我可以打印页面的源代码 但我认为这与文件不同 我不必只将接收到的数据从
  • 如何使用不同的基本路径托管 Blazor WebAssembly 应用程序

    我有一个 Blazor Webassemble NET 托管应用程序 在我们托管它的服务器上 应用程序的基本路径将是mydomain com coolapp 因此 为了尝试让应用程序在服务器上正确呈现 我一直遵循本页 应用程序基本路径 部分
  • copy_from_user() 错误:目标大小太小

    我正在为内核模块编写 ioctl 处理程序 我想从用户空间复制数据 当我编译禁用优化的代码时 O0 gflags 编译器返回以下错误 include linux thread info h 136 17 error call to bad
  • 如何在 C++ 中为指针“this”赋值

    在函数中 如何分配this一个新的价值 您可以分配对象this点于 this XY 但你不能分配直接值this this XY Error Expression is not assignable
  • 从结构调用 C++ 成员函数指针

    我找到了有关调用 C 成员函数指针和调用结构中的指针的信息 但我需要调用结构内部存在的成员函数指针 但我无法获得正确的语法 我在类 MyClass 的方法中有以下代码片段 void MyClass run struct int MyClas
  • Windows Phone 7 - ScrollViewer 值已更改

    我一直在寻找解决方案 但无法找到正确的解决方案 我的网格宽度为 960 并且有ScrollViewer在里面 现在我想知道滚动时滚动的值 水平偏移 我找到的所有解决方案都是针对 wpf silverlight 的 它对我不起作用 Edit
  • 公交车公共交通算法

    我正在开发一个可以查找公交路线的离线 C 应用程序 我可以提取时间表 巴士 路线数据 我正在寻找适用于基本数据的最简单的解决方案 可以使用什么算法来查找从巴士站 A 到巴士站 B 的路线 是否有适用于 C Java 的开源解决方案 数据库的
  • 自己绘制的WPF自定义滑块

    这是我关于堆栈溢出的第一个问题 所以不要踢它 我在尝试创建 Mac 风格的滑块控件时遇到问题 我已经发现这个解决方案 http www codeproject com KB miscctrl MAC Slider aspx我已经在我的解决方
  • 从图像创建半透明光标

    是否可以从图像创建光标并使其半透明 我目前正在拍摄自定义图像并覆盖鼠标光标图像 如果我可以将其设为半透明 那就太好了 但不是必需的 销售人员喜欢闪亮的 目前正在做这样的事情 Image cursorImage customImage Get
  • 使用 STL 流时如何格式化我自己的对象?

    我想将我自己的对象输出到 STL 流 但具有自定义格式 我想出了这样的东西 但由于我之前从未使用过 locale 和 imbue 所以我不知道这是否有意义以及如何实现 MyFacet 和operator 所以我的问题是 这是否有意义以及如何
  • 使用任一默认捕获模式时,这是通过复制捕获还是 (*this) 通过引用捕获?是一样的吗?

    当我看到以下工作时我有点困惑 struct A void g void f g 但后来我发现this https stackoverflow com a 16323119 5825294答案非常详细地解释了它是如何工作的 本质上 它归结为t
  • 将 AutomationID 与 ListView 结合使用

    我正在尝试将 AutomationId 附加到列表视图中的项目 理想情况下 将项目名称绑定到显示的项目
  • 如何在Windows窗体中打开进程

    我想在我的 Windows 窗体应用程序中打开进程 例如 我希望当用户按下 Windows 窗体容器之一中的按钮时 mstsc exe 将打开 如果他按下按钮 它将在另一个容器上打开 IE DllImport user32 dll SetL
  • 为什么这个位图图像在加载后会改变大小?

    快速提问 我有这个1000 1000位图图像 我使用这个例程来加载它 private BitmapSource initialBitmap new BitmapImage new Uri C Users Desktop Original b
  • 在 Visual Studio 2012 Express 中设置 C++ 调试环境

    我需要调试的应用程序需要设置环境变量 这在 Visual Studio 2012 中似乎非常复杂 我想做类似的事情 set path c foo c bar c windows c program files application set
  • 查找数组中的多个索引

    假设我有一个像这样的数组 string fruits watermelon apple apple kiwi pear banana 是否有一个内置函数可以让我查询 apple 的所有索引 例如 fruits FindAllIndex ap
  • 如何防止 Lotus Notes 用户转发或复制通过 System.Net.Mail 发送的邮件?

    我想使用 SMTP 客户端 uiing microsft net 以 C 作为编程语言发送电子邮件 但是对于通过SMTP客户端发送的电子邮件 我们是否可以添加 禁止转发 或 禁止复制 等安全功能 我不希望电子邮件的收件人转发或复制电子邮件的
  • 为什么存在系统调用

    我一直在阅读有关系统调用及其在 Linux 中如何工作的内容 我还有更多的阅读要做 但我读过的一件事都没有回答 那就是 为什么我们需要系统调用 我知道系统调用是用户空间程序要求内核执行某些操作的请求 但我的问题基本上是 为什么用户空间程序本
  • java有类似C#的属性吗? [复制]

    这个问题在这里已经有答案了 C 属性 我的意思是 get 和 set 方法 是一个非常有用的功能 java 也有类似 C 的属性吗 我的意思是我们如何在 java 中实现类似以下 C 代码的内容 public string Name get
  • 如何使用 Microsoft Graph API 更新 MailboxSettings

    我想从不同的日历更新邮箱设置 如何构建可以通过 Microsoft Graph 更新 MailboxSetting 的请求 这是我的代码示例 但有例外 代码示例 User obj GraphServiceClient Users roomC

随机推荐

  • c/c++中读入字符串(包含空格)

    1 scanf函数 scanf函数一般格式为scanf s st 但scanf默认回车和空格是输入不同组之间的间隔和结束符号 所以输入带空格 tab或者回车的字符串是不可以的 解决方法如下 利用格式符 它的作用为扫描字符集合 Scanf c
  • 【Transformer】21、AdaViT: Adaptive Tokens for Efficient Vision Transformer

    文章目录 一 背景 二 方法 三 效果 一 背景 Transformer 在多个任务上都取得了亮眼的表现 在计算机视觉中 一般是对输入图像切分成多个 patch 然后计算 patch 之间的自注意力实现下游任务 但由于自注意力机制的计算量是
  • ajax跨域session失效,request跨域获取session失效

    如下代码 传到另外一个域名就获取不到session了 localhost 12402 Home Index Session MemberUser 123456 string url api Home GetTop8FileDown stri
  • 【算法】直接插入排序解析

    活动地址 CSDN21天学习挑战赛 作者 柒号华仔 个人主页 欢迎访问我的主页 个人信条 星光不问赶路人 岁月不负有心人 个人方向 主要方向为5G 同时兼顾其他网络协议 编解码协议 C C linux 云原生等 感兴趣的小伙伴可以关注我 一
  • 正则表达式分割图片和匹配图片正则

    正则表达式分割图片 正则表达式 又称规则表达式 英语 Regular Expression 在代码中常简写为regex regexp或RE 计算机科学的一个概念 正则表达式通常被用来检索 替换那些符合某个模式 规则 的文本 正则表达式是对字
  • Centos7一点心德

    1 在centos7中发现没有table键补全的命令 需要手动去输出 效率不高 但是yum提供了自动补的命令安装 root localhost systemctl restart htt 死活补全不了 常用的命令还可以接受 碰到不常用的命令
  • 【大数据之Kafka】十三、Kafka消费者生产经验之分区的分配及再平衡、数据积压和消费者事务

    1 分区的分配及再平衡 一个consumer group中有多个consumer组成 一个 topic有多个partition组成 使用分区分配策略决定由哪个consumer来消费哪个partition的数据 Kafka有四种主流的分区分配
  • 增加tomcat并发量

    之前在做tomcat的最大并发量测试 现总结如下 tomcat默认的连接是线程阻塞的 即protocol配置为 HTTP 1 1 那么tomcat的最大连接数就受maxThreads和account的限制 maxThreads是最大的线程数
  • Altium Designer 19.1.18 - 将修改后的 PCB 封装更新到当前 PCB 中

    文章目录 将修改后的 PCB 封装更新到当前 PCB 中 参考 将修改后的 PCB 封装更新到当前 PCB 中 打开 PCB Library 选择需要更新到当前 PCB 中的 PCB 封装 使用鼠标右键选择 Update PCB With
  • 一文详解微服务架构

    要理解微服务 首先要先理解不是微服务的那些 通常跟微服务相对的是单体应用 即将所有功能都打包成在一个独立单元的应用程序 从单体应用到微服务并不是一蹴而就的 这是一个逐渐演变的过程 本文将以一个网上超市应用为例来说明这一过程 最初的需求 几年
  • 火柴棒等式 C语言

    Problem Description 给你n根火柴棍 你可以拼出多少个形如 A B C 的等式 等式中的A B C是用火柴棍拼出的整数 若该数非零 则最高位不能是0 用火柴棍拼数字0 9的拼法如图所示 注意 1 加号与等号各自需要两根火柴
  • 微信中发现的问题,做一分析(见同目录其他文)

    1 基本语法 这包括static final transient等关键字的作用 foreach循环的原理等等 今天面试我问你static关键字有哪些作用 如果你答出static修饰变量 修饰方法我会认为你合格 答出静态块 我会认为你不错 答
  • linux 网络编程---->多路复用:select实例!

    好吧 我承认找了好久 网上都没有像样的完整的实例 然后自己参照书自己写一个吧 gt server 端代码 gt server c include
  • 上传图片的方法(大白话讲解)

    上传图片的方法 在上传文件的时候需要知道其原理 因为我们的数据库是无法存储数据的 所以我们只能使用地址来找 所以数据库中应该村的是文件路径 其次上传图片是属于上传文件的一种方式 所以也要学会上传文件的方法 在之后呢也要注意上传图片和对象的关
  • allowedOriginPatterns和allowedOrigins方法有什么不同

    allowedOriginPatterns 和 allowedOrigins 都是用来设置允许跨域请求的来源 其中 allowedOriginPatterns 是在 Spring 5 3 版本引入的新方法 而 allowedOrigins
  • qt layout 颜色_Qt开源作品6-通用视频控件

    一 前言 在之前做的视频监控系统中 根据不同的用户需要 做了好多种视频监控内核 有ffmpeg内核的 有vlc内核的 有mpv内核的 还有海康sdk内核的 为了做成通用的功能 不同内核很方便的切换 比如pro直接改一个DEFINE的变量名
  • Liunx下Intel无线网卡驱动安装

    首先查看网卡型号 指令 lspci grep i net 如果是Intel的无线网卡 可以参考以下方法 1 在这个页面中查找对应的无线网卡型号 以我的8260为例 前面是型号 后面是最低系统内核版本 往下翻可以查看各个型号的下载链接 系统内
  • 用户id生成规则_阿里/网易/美团/58用户画像中的ID体系建设

    前言 梳理完标签画像体系的业务需求后 作为数据产品经理 就要开始了对画像体系的整体设计 其中首要遇到的就是用户ID体系的打通相关的问题 公司各业务线ID繁多 数据割裂 如何才能尽可能关联更多的数据 以准确的描绘出一个用户的画像呢 接下来我们
  • MySQL的系统数据库

    information schema 用途 存储数据库对象相关信息 例如用户表 列 权限 字符集 分区等 表 TABLES 提供了关于数据库中表的信息 含视图 SHOW TABLES FROM DatabaseName的结果取自该表 COL
  • QT CREATOR 插件开发:添加新的工程类型(下)

    Core BaseFileWizard 类Core BaseFileWizard在 coreplugin basefilewizard h 文件中声明 class CORE EXPORT BaseFileWizard public IWiz