初识 Qt Creator 插件开发

本文通过几个示例,来学习如何开发 Qt Creator 插件。

首先,先确定几个目录的位置:

  • Qt 安装目录 - /usr/software/Qt5.13.1
  • Qt Creator 安装目录 - /data/qt-creator-opensource-src-4.10.1

目录的位置不是固定的,可以按照自己的习惯选择安装时的目录。

准备工作

源码下载

注意,安装 qt 时,请最大安装,因为编译 qt creator 需要依赖所有的 qt 库,非最大安装会出现编译错误

首先,需要安装 qt,建议下载离线安装包,本示例使用 Qt 5.13.1
http://download.qt.io/official_releases/qt/5.13/5.13.1/qt-opensource-linux-x64-5.13.1.run
或者访问下载目录选择需要的版本下载
http://download.qt.io/official_releases/qt/

还需下载 qt creator 源码,本示例使用 Qt Creator 4.10.1
http://download.qt.io/official_releases/qtcreator/4.10/4.10.1/qt-creator-opensource-src-4.10.1.tar.gz
或者访问下载目录选择需要的版本下载
http://download.qt.io/official_releases/qtcreator/

编译

注意,编译时间较长,请耐心等待

运行一下命令执行编译

# 进入 qt creator 安装目录
$ cd /data/qt-creator-opensource-src-4.10.1

# 运行 qmake
$ /usr/software/Qt5.12.5/5.12.5/gcc_64/bin/qmake -r

# 开始编译
$ make -j8

这里执行 make -j8,表示使用8核运行编译,视编译机器的cpu数决定 -jN 参数中N的值,最大与cpu核心数相等,可缩短编译时间

编译完成后会在 qt creator 安装目录中的 bin 目录中生成可执行文件,运行 ./bin/qtcreator 启动ide。

创建插件项目

在 Qt Creator 中选择 文件 > 新建文件或项目 > Library > Qt Creator 插件,之后根据项目向导完成插件项目的创建。

注意,向导第三步 插件信息 页面中的 Qt Creator源文件Qt Creator构建 处需要选择 Qt Creaotr 安装目录,这里选择 /data/qt-creator-opensource-src-4.10.1

初识 Qt Creator 插件开发_第1张图片
插件信息页

项目创建完成后,目录结构如下:


初识 Qt Creator 插件开发_第2张图片
项目结构
目录结构

详解

接下来将分析主要的项目文件

Demo1.json.in
该定义了插件的信息,插件编译时会生成名为 Demo1.json 的文件。

这里需要注意一下,修改 Demo1.json.in 文件,将该文件的中字符串key和value前后的双引号 " 替换成 \",否则插件可能无法运行。

{
    \"Name\" : \"Demo1\",
    \"Version\" : \"0.0.1\",
    \"CompatVersion\" : \"0.0.1\",
    \"Vendor\" : \"abeir\",
    \"Copyright\" : \"(C) SyberOS\",
    \"License\" : \"Put your license information here\",
    \"Description\" : \"Put a short description of your plugin here\",
    \"Url\" : \"http://www.syberos.com\",
    $$dependencyList
}

demo1.pro

DEFINES += DEMO1_LIBRARY

SOURCES +=         demo1plugin.cpp

HEADERS +=         demo1plugin.h         demo1_global.h         demo1constants.h

isEmpty(IDE_SOURCE_TREE): IDE_SOURCE_TREE = $$(QTC_SOURCE)
isEmpty(IDE_SOURCE_TREE): IDE_SOURCE_TREE = "/data/qt-creator-opensource-src-4.10.1"

isEmpty(IDE_BUILD_TREE): IDE_BUILD_TREE = $$(QTC_BUILD)
isEmpty(IDE_BUILD_TREE): IDE_BUILD_TREE = "/data/qt-creator-opensource-src-4.10.1"

QTC_PLUGIN_NAME = Demo1
QTC_LIB_DEPENDS +=     # nothing here at this time

QTC_PLUGIN_DEPENDS +=     coreplugin

QTC_PLUGIN_RECOMMENDS +=     # optional plugin dependencies. nothing here at this time

include($$IDE_SOURCE_TREE/src/qtcreatorplugin.pri)

QTC_SOURCE 和 QTC_BUILD 变量指明 Qt Creator 的源码目录和构建目录。可以通过设置环境变量的方式修改至其他路径。由于之前创建插件项目时,指定了源码目录和构建目录,在这里都指向了 /data/qt-creator-opensource-src-4.10.1
QTC_LIB_DEPENDS 指定依赖的库。
QTC_PLUGIN_DEPENDS 指定依赖的其他插件。

demo1plugin.h

#ifndef DEMO1_H
#define DEMO1_H
#include "demo1_global.h"

#include 

namespace Demo1 {
namespace Internal {

class Demo1Plugin : public ExtensionSystem::IPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Demo1.json")

public:
    Demo1Plugin();
    ~Demo1Plugin() override;

    bool initialize(const QStringList &arguments, QString *errorString) override;
    void extensionsInitialized() override;
    ShutdownFlag aboutToShutdown() override;

private:
    void triggerAction();
};

} // namespace Internal
} // namespace Demo1


#endif // DEMO1_H

IPlugin 类是插件的基类,所有的插件都需要继承该类,并实现其中的虚函数。
IPlugin 提供了一系列函数,用于插件加载到一定阶段时进行回调。下面我们按照插件加载的顺序介绍 IPlugin 提供的一些函数。

当插件描述文件读取、并且所有依赖都满足之后,插件将开始进行加载。这一步分为三个阶段:

  1. 所有插件的库文件按照依赖树从根到叶子的顺序进行加载。
  2. 按照依赖树从根到叶子的顺序依次调用每个插件的 IPlugin::initialize() 函数。
  3. 按照依赖树从叶子到根的顺序依次调用每个插件的 IPlugin::extensionsInitialized() 函数。
virtual bool initialize(const QStringList &arguments, QString *errorString) = 0;

该函数会在插件加载完成,并且创建了插件对象之后调用。该函数返回值是bool类型,当插件初始化成功,返回 true;否则,由 errorString 参数将错误信息返出。当前插件的 initialize() 函数会在所有依赖的插件都调用了 initialize() 函数之后被调用 。如果插件需要共享一些对象,就应该将这些共享对象放在这个函数中。

virtual void extensionsInitialized() = 0;

该函数在 initialize() 函数调用完毕、并且所依赖插件的 extensionsInitialized() 函数调用完毕之后被调用。当运行到这一阶段时,插件所依赖的其它插件都已经初始化完毕。这也暗示着,该插件所依赖的各个插件提供的可被共享的对象都已经创建完毕,可以正常使用了。

virtual bool delayedInitialize() { return false; }

该函数会在 extensionsInitialized() 函数调用完成,并且所依赖插件的 delayedInitialize() 函数也调用完成之后才被调用。delayedInitialize() 函数会在程序运行之后才被调用,并且距离程序启动有几个毫秒的间隔。为避免不必要的延迟,插件对该函数的实现应该尽快返回。该函数的意义在于,有些插件可能需要进行一些重要的启动工作;这些工作虽然不必在启动时直接完成,但也应该在程序启动之后的较短时间内完成。该函数默认返回false,即不需要延迟初始化。

virtual ShutdownFlag aboutToShutdown() { return SynchronousShutdown; }

signals:
    void asynchronousShutdownFinished();

aboutToShutdown() 函数应该用于与其它插件断开连接、隐藏所有 UI、优化关闭操作,会以插件初始化的相反顺序调用,即先调用当前插件的 aboutToShutdown() 函数,再依次调用依赖插件的。如果插件需要延迟真正的关闭,例如,需要等待外部进程执行完毕,以便自己完全关闭,则应该返回 AsynchronousShutdown,这么做的话会进入主事件循环,等待所有返回了 AsynchronousShutdown 的插件都发出了 asynchronousShutdownFinished() 信号之后,再执行相关操作。该函数默认返回 SynchronousShutdown,即不等待其它插件关闭。

下面,我们再回过头来看看 demo1plugin.h

Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Demo1.json")

Q_PLUGIN_METADATA 这个宏用于声明插件的元数据。当实例化插件对象时,这些元数据会作为该对象的一部分。这个宏需要声明一个 IID 属性,用于标识对象实现的接口;还需要一个文件的引用FILE属性,该文件包含了插件的元数据。
使用这个宏的类必须有无参数的构造函数。在这里,Qt Creator 规定其插件的 IID 必须是 org.qt-project.Qt.QtCreatorPlugin。FILE指向了 Demo1.json 文件,但是项目里只有 Demo1.json.in,这是由于编译时,会使用 Demo1.json.in 生成 Demo1.json 文件,我们可以在编译目录下找到该文件。

demo1plugin.cpp

#include "demo1plugin.h"
#include "demo1constants.h"

#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 

namespace Demo1 {
namespace Internal {

Demo1Plugin::Demo1Plugin()
{
}

Demo1Plugin::~Demo1Plugin()
{
}

bool Demo1Plugin::initialize(const QStringList &arguments, QString *errorString)
{
    Q_UNUSED(arguments)
    Q_UNUSED(errorString)

    auto action = new QAction(tr("Demo1 Action"), this);
    Core::Command *cmd = Core::ActionManager::registerAction(action, Constants::ACTION_ID,
                                                             Core::Context(Core::Constants::C_GLOBAL));
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Meta+A")));
    connect(action, &QAction::triggered, this, &Demo1Plugin::triggerAction);

    Core::ActionContainer *menu = Core::ActionManager::createMenu(Constants::MENU_ID);
    menu->menu()->setTitle(tr("Demo1"));
    menu->addAction(cmd);
    Core::ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);

    return true;
}

void Demo1Plugin::extensionsInitialized()
{
}

ExtensionSystem::IPlugin::ShutdownFlag Demo1Plugin::aboutToShutdown()
{
    return SynchronousShutdown;
}

void Demo1Plugin::triggerAction()
{
    QMessageBox::information(Core::ICore::mainWindow(),
                             tr("Action Triggered"),
                             tr("This is an action from Demo1."));
}

} // namespace Internal
} // namespace Demo1

接下来分析一下 demo1plugin.cpp 都做了些什么。

auto action = new QAction(tr("Demo1 Action"), this);
Core::Command *cmd = Core::ActionManager::registerAction(action, Constants::ACTION_ID,
                                                             Core::Context(Core::Constants::C_GLOBAL));
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Meta+A")));
connect(action, &QAction::triggered, this, &Demo1Plugin::triggerAction);

这段代码定义了一个动作 Demo1 Action,并为该动作设置了快捷键 Ctrl+Alt+Meta+A,最后再将 triggered 信号绑定至本类中的 triggerAction 槽函数上。triggered 信号是在用户触发了动作,比如,单击或使用快捷键时发送。

Core::ActionContainer *menu = Core::ActionManager::createMenu(Constants::MENU_ID);
menu->menu()->setTitle(tr("Demo1"));
menu->addAction(cmd);
Core::ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);

这段代码创建了一个菜单,并设置了菜单名为 Demo1,最后再将菜单添加到 Qt Creator 的 工具 菜单中。
Qt Creator 提供了一些主菜单允许我们将自己创建的菜单添加进去:

  • Core::Constants::M_FILE - 文件
  • Core::Constants::M_EDIT - 编辑
  • Core::Constants::M_EDIT_ADVANCED - 编辑 > Advanced
  • Core::Constants::M_TOOLS - 工具
  • Core::Constants::M_TOOLS_EXTERNAL - 工具 > 外部
  • Core::Constants::M_WINDOW - 控件
  • Core::Constants::M_WINDOW_MODESTYLES - 控件 > Mode Selector Style
  • Core::Constants::M_WINDOW_VIEWS - 控件 > 视图
  • Core::Constants::M_HELP - 帮助
void Demo1Plugin::triggerAction()
{
    QMessageBox::information(Core::ICore::mainWindow(),
                             tr("Action Triggered"),
                             tr("This is an action from Demo1."));
}

这段代码是当我们点击 工具 > Demo1 > Demo1 Action 时,触发一个弹出框。

最后,运行 构建项目,Demo1 插件将被编译成名为 libDemo1.so 的文件并安装至 /data/qt-creator-opensource-src-4.10.1/lib/qtcreator/plugins

运行

$ /data/qt-creator-opensource-src-4.10.1/bin/qtcreator

启动 Qt Creator 就可以在 工具 菜单中找到我们的插件。

你可能感兴趣的:(初识 Qt Creator 插件开发)