Qt Creator 插件开发(2):第一个插件

学习如何编写 Qt Creator 插件最好的方法是亲自编写一个插件。在自己动手的过程中了解插件编写机制。这也是本章所要解决的问题。在这一章中,我们将创建我们的第一个插件。这个插件不会做任何事情,仅仅是为了让我们体验下开发 Qt Creator 插件的过程,以及感受下我们自己的插件同 Qt Creator 整合在一起时的那种激动之情。

我们可以在 Qt Creator 的帮助菜单中找到“关于插件…”一项。点击这个菜单项,我们就可以发现 Qt Creator 已经找到的所有插件:

QtCreator 插件列表

下面我们开始创建第一个插件。

1. 创建 Qt Creator 插件工程

首先,在 $$QT_CREATOR_ROOT/src/plugins 文件夹下建立新的文件夹 DoNothing(或许你会奇怪,为什么不是经典的 helloworld?因为 Nokia 已经提供了一个名叫 helloworld 的插件)。我们的所有源代码都会放在这个文件夹下。

然后,我们创建我们的 .pro 文件:

TEMPLATE = lib
TARGET = DoNothing
include(../../qtcreatorplugin.pri)
DESTDIR = $$IDE_PLUGIN_PATH/Galaxy
PROVIDER = Galaxy
include(../../plugins/coreplugin/coreplugin.pri)
HEADERS += DoNothingPlugin.h
SOURCES += DoNothingPlugin.cpp
OTHER_FILES += DoNothing.pluginspec

下面来逐行解释一下 .pro 文件的含义:

  1. 声明 DoNothing 是一个库,而我们的输出文件将是 DoNothing.dll;
  2. 说明 DoNothing 使用 qtcreatorplugin.pri 中定义的设置信息;
  3. 覆盖默认的输出文件夹为 $$IDE_PLUGIN_PATH/Galaxy。默认情况下,这个值将会是 $$IDE_PLUGIN_PATH/Nokia。其中,Galaxy 部分即是提供插件的公司或者组织名字;
  4. 说明 DoNothing 使用 coreplugin.pri 定义的配置信息;
  5. 提供编译插件所必需的 .h 和 .cpp 文件。

2. 标记需要编译的插件

下面,编辑 $$QT_CREATOR_ROOT/src/plugins/plugins.pro 文件,在最后面添加并保存:

SUBDIRS += plugin_DoNothing
plugin_DoNothing.subdir = DoNothing

我们可以仔细看一下 plugins.pro 文件,其中定义了所有 SUBDIRS 及其子文件夹。上面两行保证,在我们下一次编译 Qt Creator 的时候,DoNothing 插件会与其他插件一起被编译。

3.实现插件

现在,我们已经写好了项目文件,并且标记出我们的插件需要同 Qt Creator 一起编译。下面,我们需要为我们的插件编写实际的代码。所有的插件都需要实现 IPlugin 接口。我们的 DoNothing 当然也不例外。

首先创建 $$QT_CREATOR_ROOT/src/plugins/DoNothing/DoNothingPluigin.h 文件,其内容为:

#ifndef DONOTHINGPLUGIN_H
#define DONOTHINGPLUGIN_H

#include <extensionsystem/iplugin.h>

class DoNothingPlugin : public ExtensionSystem::IPlugin
{
public:
    DoNothingPlugin();
    ~DoNothingPlugin();

    void extensionsInitialized();
    bool initialize(const QStringList & arguments, QString * errorString);
    void shutdown();
};

#endif // DONOTHINGPLUGIN_H

正如你所看到的一样,DoNothingPlugin类实现了IPlugin接口,除此之外别无它物。下面来看一下 cpp 文件:

#include "DoNothingPlugin.h"
#include <QtPlugin>
#include <QStringList>

DoNothingPlugin::DoNothingPlugin()
{
    // Do nothing
}

DoNothingPlugin::~DoNothingPlugin()
{
    // Do notning
}

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

    return true;
}

void DoNothingPlugin::extensionsInitialized()
{
    // Do nothing
}

void DoNothingPlugin::shutdown()
{
    // Do nothing
}

Q_EXPORT_PLUGIN(DoNothingPlugin)

最前面是构造函数和析构函数。由于我们的插件没有任何需要初始化的局部变量,也没有任何组件或者动作,因此这两个函数都是空的。

initialize()函数会在 Qt Creator 请求插件初始化时被调用。这个函数通常用于初始化插件的内部状态,向 Qt Creator 注册 actions/objects 等。当插件依赖的所有资源都被加载之后,这个函数才会被调用。由于我们的插件不做任何事情,因此,我们在这个函数中仅仅返回 true,用于告诉 Qt Creator 本插件已经初始化成功。如果初始化不成功(不论什么原因),都应该在 errMsg 中存储人可读的错误信息,供 Qt Creator 在界面上显示出来。

extensionsInitialized()函数在插件初始化之后被调用(例如initialize()函数调用之后)。这个函数会由第一个依赖于本插件的其他插件进行调用。

shutdown()函数在插件即将被卸载的时候调用。

最后,我们使用Q_EXPORT_PLUGIN()宏将类导出。

4. 编写 pluginspec 文件

每个插件都需要提供一个 pluginspec,用于提供关于插件的元数据,例如版本、依赖项等。我们的插件的 pluginspec 文件如下所示:

<plugin name="DoNothing" version="0.0.1" compatVersion="2.2.1">
    <vendor>Galaxy.org</vendor>
    <copyright>(C) 2010-2011 Galaxy.org</copyright>
    <license>
Do anything you want.
    </license>
    <description>A plugin that does nothing.</description>
    <url>http://www.devbean.net</url>
    <dependencyList>
        <dependency name="Core" version="2.2.1"/>
    </dependencyList>
</plugin>

pluginspec 就是一个 XML 文件。它提供了以下信息:

  1. 插件名字。这个名字通常用于插件的文件名(在我们的例子中,Windows 平台下就是 DoNothing.dll,Unix 上则是 libDoNothing.so)。
  2. 插件版本号。
  3. 要求的 Qt Creator 的版本号。
  4. 插件提供者。
  5. 版权。
  6. 协议文本。
  7. 插件描述。
  8. 插件提供者的 URL。
  9. 依赖列表。列出本插件所需要的所有依赖插件,Qt Creator 将保证这里列出的所有依赖项都加载并且初始化之后采取加载我们的插件。

注意,pluginspec 文件应该和插件的 .pro 文件在同一目录下。这里,我们目前的目录结构如下所示:

DoNothing 插件文件

5. 编译插件

打开命令提示符,进入我们上一章创建的 build 文件夹,执行如下命令:

qmake ..\qtcreator.pro –r
mingw32-make

当编译完成之后(不要担心,这次编译没有那么长时间),我们可以在 $$QT_CREATOR_BUILD_ROOT\build\lib\qtcreator\plugins 下面会有一个 Galaxy 文件夹,里面是我们编译的插件的文件。

6. 查看插件

运行 Qt Creator,在前面我们说的“已安装插件”的对话框中可以找到我们的 DoNothing 插件:

DoNothing 加载成功

现在,我们的第一个插件已经编译完成了!

7. 在 Qt Creator 代码树外编译插件

按照前面的步骤,我们已经编译好我们的第一个插件。但是,这里有一个很严重的问题:插件的源代码同 Qt Creator 的代码混杂在一起。这是不好的行为,因为你不能为了测试一个插件去重新编译 Qt Creator——你也已经见识到,编译 Qt Creator 很耗时间——并且,因为你是 Qt Creator 插件的第三方提供商,你不能指望 Qt Creator 会把你的插件代码放进其代码树。所以,我们必须有一种机制,能够让我们在 Qt Creator 代码树外编译插件。

能够让我们在 Qt Creator 代码树外编译插件的关键因素是一个特殊的 .pro 文件。下面,我们修改一下 DoNothing 的 .pro 文件,让它支持从 Qt Creator 代码树外编译插件。

下面我们列出了目前的目录结构:

描述 目录
Qt Creator 源代码 E:\lib\QtCreator\qt-creator-2.2.1-src
Qt Creator 构建目录 E:\lib\QtCreator\build
DoNothing 插件目录 E:\lib\QtCreator\plugins\DoNothing这个目录下包括:

  • DoNothing.pluginspec
  • DoNothing.pro
  • DoNothingPlugin.cpp
  • DoNothingPlugin.h
插件目标目录 E:\lib\QtCreator\build\lib\qtcreator\plugins\Galaxy

下面,我们将 E:\lib\QtCreator\plugins\DoNothing 中的 DoNothing.pro 文件修改为:

QTC_SOURCE         = E:/lib/QtCreator/qt-creator-2.2.1-src
QTC_BUILD             = E:/lib/QtCreator/build

TEMPLATE              = lib
TARGET                 = DoNothing
IDE_SOURCE_TREE = $$QTC_SOURCE
IDE_BUILD_TREE     = $$QTC_BUILD
PROVIDER              = Galaxy
DESTDIR                = $$QTC_BUILD/lib/qtcreator/plugins/Galaxy
LIBS                     += -L$$QTC_BUILD/lib/qtcreator/plugins/Nokia

include($$QTC_SOURCE/src/qtcreatorplugin.pri)
include($$QTC_SOURCE/src/plugins/coreplugin/coreplugin.pri)

HEADERS              = DoNothingPlugin.h
SOURCES              = DoNothingPlugin.cpp
OTHER_FILES        = DoNothingPlugin.pluginspec

QTC_SOURCEQTC_BUILD 变量指明 Qt Creator 的源代码目录和构建目录。如果你将这些值设置为环境变量,那么只要使用 $$(QTC_BUILD) 就可以了。

IDE_SOURCE_TREEIDE_BUILD_TREE 由 qtcreatorplugin.pri 使用,指明其 include 和 library 的路径。

PROVIDERDESTDIR 目录必须在 include($$QTC_SOURCE/src/qtcreatorplugin.pri) 语句之前设置。这是因为这两个变量的默认值分别是 Nokia 和 $$IDE_BUILD_TREE/lib/qtcreator/plugins/Nokia。默认情况下,qtcreatorplugin.pri 假设所有插件可能依赖的库都是在 DESTDIR 中。如果我们的 DESTDIR 与默认值 (Nokia)不同,我们就应当显式设置。

其它代码同前面所说的都是一样的了。

然后,我们进入 plugins/DoNothing 里面,使用

qmake
ming32-make

语句即可完成编译。

附件下载:DoNothing 插件文件

24 Comments

  1. ty 2011年11月29日
    • DevBean 2011年11月29日
      • ty 2013年1月28日
  2. 小马 2011年12月30日
    • 小马 2011年12月30日
      • DevBean 2011年12月30日
  3. 毕爽 2013年5月5日
    • 毕爽 2013年5月5日
    • 豆子 2013年5月5日
      • 毕爽 2013年5月10日
  4. 雷鸣的家 2013年6月3日
    • 豆子 2013年6月6日
      • 雷鸣的家 2013年6月6日
  5. kangaxx 2013年9月25日
    • 豆子 2013年9月25日
      • kangaxx 2013年9月27日
        • 豆子 2013年9月28日
          • kangaxx 2013年9月29日
  6. Toxsch 2013年12月13日
    • 豆子 2013年12月14日
  7. 郭铠源 2014年6月6日
    • 豆子 2014年6月12日
  8. 阿南 2016年3月15日
    • 豆子 2016年3月15日

Leave a Reply