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

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

30 3.7K

学习如何编写 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>https://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 插件文件

30 评论

ty 2011年11月29日 - 17:56

😆 帅呆了

回复
DevBean 2011年11月29日 - 21:37

过奖哦

回复
ty 2013年1月28日 - 11:12

😀 😀
时隔一年多 又回来看这系列文章了 很不错 不过这次事真的要开发插件了 呵呵

回复
小马 2011年12月30日 - 16:30

make完了,关于插件那 也出来了,先在想卸载,请问怎么搞

回复
小马 2011年12月30日 - 16:39

在build目录直接把插件删了,倒是不显示插件了,只是不知这样是否有其它垃圾留下?

回复
DevBean 2011年12月30日 - 20:32

应该是直接删除文件夹就可以了。既然是插件,那么除了 setting 之外,其它都应该是可插拔的,否则就是去了插件的优势。

回复
毕爽 2013年5月5日 - 16:14

你好 为什么用ubuntu系统编译显示 找不到这个文件???
还有 qt5对qt4的改进大么??qt4能编译的某些文件 qt5是否需要qt4_support??

回复
毕爽 2013年5月5日 - 16:18

是extensionsystem/iplugin.h 这个文件

回复
豆子 2013年5月5日 - 17:23

最新版本的 Qt Creator 代码是兼容 Qt5 的,所以找不到文件应该是编译路径问题。Qt5 对于 Qt4 改动不算小,但是大部分常用接口没有变化;但是 Qt5 进行了很细模块化,需要在编译时注意选择添加的模块。比如 Qt4 的 GUI 程序增加 QT+=gui 已经足够,但是 Qt5 则应该添加 QT+=gui widgets

回复
毕爽 2013年5月10日 - 19:26

一直在忙考试 就没来得及回复 ,我再试试 谢谢啦

回复
雷鸣的家 2013年6月3日 - 09:08

想问下,plugin的调试只能用重启creator的方法么?有没有可以直接调试的方式呢?

回复
豆子 2013年6月6日 - 14:39

现在貌似只能这样子的

回复
雷鸣的家 2013年6月6日 - 14:42

好吧,那谢谢你啦。。呵呵。。

回复
kangaxx 2013年9月25日 - 17:01

豆子老大,请问您在CentOS 6.4上编译安装过QT CREATOR么?我这台电脑之前已经安装了Qt5和QT CREATOR 2.8.1,但是似乎时INSTALL包直接安装的,要开发插件是不是一定要重新编译安装QT CREATOR呢?

回复
豆子 2013年9月25日 - 22:34

如果你要开发 Qt Creator 的插件,最好自己编译一个 debug 版本的 Qt Creator,以便能够加载 debug 版本的插件用于调试(如果你编译 debug 版本的插件,就要求 Qt Creator 加载 debug 版本的 Qt 库,而安装版是 release 的,不能调试)。如果你不需要调试,只能使用输出语句调试,也是可以的

回复
kangaxx 2013年9月27日 - 16:52

hoho,多谢豆子老大,我已经成功编译QT Creator了,目前在用2.8.1版本,正在学习您的教程,我想把我做的插件so文件直接copy到别人电脑上用,最好不要把代码啥的copy来copy去,这样代码管理会比较混乱,可行么?多谢哦!

回复
豆子 2013年9月28日 - 15:15

最终以二进制形式发布当然是可行的,一般是把插件复制到对应的文件夹下重启 Qt Creator 就可以找到了。为方便用户,你可以制作一个脚本自动完成复制等操作。

回复
kangaxx 2013年9月29日 - 10:12

多谢豆子兄!

Toxsch 2013年12月13日 - 16:26

Qt5下,插件导出不能再依靠Q_EXPORT_PLUGIN宏了
在iplugin.h中,有如下定义
// The macros Q_EXPORT_PLUGIN, Q_EXPORT_PLUGIN2 become obsolete in Qt 5.
#if QT_VERSION >= 0x050000
# if defined(Q_EXPORT_PLUGIN)
# undef Q_EXPORT_PLUGIN
# undef Q_EXPORT_PLUGIN2
# endif
# define Q_EXPORT_PLUGIN(plugin)
# define Q_EXPORT_PLUGIN2(function, plugin)
#else
# define Q_PLUGIN_METADATA(x)
#endif
需要在iPlugin的子类中加入
Q_PLUGIN_METADATA(IID "xxx" FILE "xxx.json")

回复
豆子 2013年12月14日 - 21:44

是的,Qt5 的插件系统做了全新的设计,所以和 Qt4 的不兼容。

回复
郭铠源 2014年6月6日 - 20:30

用 MingW_32 编译 qt-creator-opensource-src-3.1.1 Debug 版本会出现以下问题( 我的操作系统是 Win 8.1 64 bit ):

Starting C:\Sources\qt-creator-opensource-src\build\Debug\bin\qtcreator.exe...
QML debugging is enabled. Only use this in a safe environment.

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
程序异常结束。
C:\Sources\qt-creator-opensource-src\build\Debug\bin\qtcreator.exe crashed

另外希望豆子修改下现有教程,能跟版本同步下。

回复
豆子 2014年6月12日 - 10:13

这个错误是内存分配的问题,有可能与环境有关系?因为原来的教程也是根据网上的一篇有关 1.x 的版本来看的,所以现在一直没有更新。

回复
阿南 2016年3月15日 - 15:39

你好,我的插件插入进去了,但显示"libDoNothing.so“中的插件验证数据不匹配".
在已安装插件列表中有donothing插件,但前面的状态不是对号,而是一个差号.

请问插件验证数据不匹配是什么意思,谢谢.

回复
豆子 2016年3月15日 - 20:10

一般原因是插件编写错误,可能是缺少 Q_INTERFACES、Q_EXPORT_PLUGIN2 等宏。另外,当时文章是 Qt 4 的版本,注意最新版的 Qt Creator 是 Qt 5 的,可能是这里出了问题。

回复
zyd 2020年2月22日 - 19:16

您好看了你的教程我是用vs编译的编译完成运行时显示“核心载入失败,无法加载D:\QT\Qtcreator\build\lib\qtcreator\plugins\core.dll库,找不到指定的模块”但是我这个目录下面是有这个模块的

回复
豆子 2020年2月28日 - 10:25

会不会是这个路径不在运行时的环境里面?所以找不到?

回复
wangchong 2020年2月27日 - 21:24

你好,我按照老师你的步骤操作,提示src/plugins/coreplugin/coreplugin.pri这个文件,有coreplugin.pro!
几个QtCreator版本的源码我都下载了,还是没找到,请问这是什么原因呢?

回复
豆子 2020年2月28日 - 10:24

可能是版本架构又有调整吧,新版本可以看看帮助文档,帮助里面现在已经有了关于 Qt Creator 插件的相关内容,可以参考下。

回复
hello 2020年9月16日 - 17:35

请教楼主 相比于QT自带l的Plugin ,l工程中是否用CTK Plugin Framework更多一些?

回复
豆子 2020年9月21日 - 17:20

这个还是看项目需求吧,个人感觉如果官方的功能能够满足,尽量以官方的为主,毕竟社区的框架不能保证以后是否还会维护。

回复

回复 wangchong 取消回复

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2