学习如何编写 Qt Creator 插件最好的方法是亲自编写一个插件。在自己动手的过程中了解插件编写机制。这也是本章所要解决的问题。在这一章中,我们将创建我们的第一个插件。这个插件不会做任何事情,仅仅是为了让我们体验下开发 Qt Creator 插件的过程,以及感受下我们自己的插件同 Qt Creator 整合在一起时的那种激动之情。
我们可以在 Qt Creator 的帮助菜单中找到“关于插件...”一项。点击这个菜单项,我们就可以发现 Qt Creator 已经找到的所有插件:
下面我们开始创建第一个插件。
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 文件的含义:
- 声明 DoNothing 是一个库,而我们的输出文件将是 DoNothing.dll;
- 说明 DoNothing 使用 qtcreatorplugin.pri 中定义的设置信息;
- 覆盖默认的输出文件夹为 $$IDE_PLUGIN_PATH/Galaxy。默认情况下,这个值将会是 $$IDE_PLUGIN_PATH/Nokia。其中,Galaxy 部分即是提供插件的公司或者组织名字;
- 说明 DoNothing 使用 coreplugin.pri 定义的配置信息;
- 提供编译插件所必需的 .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 文件。它提供了以下信息:
- 插件名字。这个名字通常用于插件的文件名(在我们的例子中,Windows 平台下就是 DoNothing.dll,Unix 上则是 libDoNothing.so)。
- 插件版本号。
- 要求的 Qt Creator 的版本号。
- 插件提供者。
- 版权。
- 协议文本。
- 插件描述。
- 插件提供者的 URL。
- 依赖列表。列出本插件所需要的所有依赖插件,Qt Creator 将保证这里列出的所有依赖项都加载并且初始化之后采取加载我们的插件。
注意,pluginspec 文件应该和插件的 .pro 文件在同一目录下。这里,我们目前的目录结构如下所示:
5. 编译插件
打开命令提示符,进入我们上一章创建的 build 文件夹,执行如下命令:
qmake ..\qtcreator.pro –r mingw32-make
当编译完成之后(不要担心,这次编译没有那么长时间),我们可以在 $$QT_CREATOR_BUILD_ROOT\build\lib\qtcreator\plugins 下面会有一个 Galaxy 文件夹,里面是我们编译的插件的文件。
6. 查看插件
运行 Qt Creator,在前面我们说的“已安装插件”的对话框中可以找到我们的 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这个目录下包括:
|
插件目标目录 | 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_SOURCE 和 QTC_BUILD 变量指明 Qt Creator 的源代码目录和构建目录。如果你将这些值设置为环境变量,那么只要使用 $$(QTC_BUILD) 就可以了。
IDE_SOURCE_TREE 和 IDE_BUILD_TREE 由 qtcreatorplugin.pri 使用,指明其 include 和 library 的路径。
PROVIDER 和 DESTDIR 目录必须在 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 评论
😆 帅呆了
过奖哦
😀 😀
时隔一年多 又回来看这系列文章了 很不错 不过这次事真的要开发插件了 呵呵
make完了,关于插件那 也出来了,先在想卸载,请问怎么搞
在build目录直接把插件删了,倒是不显示插件了,只是不知这样是否有其它垃圾留下?
应该是直接删除文件夹就可以了。既然是插件,那么除了 setting 之外,其它都应该是可插拔的,否则就是去了插件的优势。
你好 为什么用ubuntu系统编译显示 找不到这个文件???
还有 qt5对qt4的改进大么??qt4能编译的某些文件 qt5是否需要qt4_support??
是extensionsystem/iplugin.h 这个文件
最新版本的 Qt Creator 代码是兼容 Qt5 的,所以找不到文件应该是编译路径问题。Qt5 对于 Qt4 改动不算小,但是大部分常用接口没有变化;但是 Qt5 进行了很细模块化,需要在编译时注意选择添加的模块。比如 Qt4 的 GUI 程序增加 QT+=gui 已经足够,但是 Qt5 则应该添加 QT+=gui widgets
一直在忙考试 就没来得及回复 ,我再试试 谢谢啦
想问下,plugin的调试只能用重启creator的方法么?有没有可以直接调试的方式呢?
现在貌似只能这样子的
好吧,那谢谢你啦。。呵呵。。
豆子老大,请问您在CentOS 6.4上编译安装过QT CREATOR么?我这台电脑之前已经安装了Qt5和QT CREATOR 2.8.1,但是似乎时INSTALL包直接安装的,要开发插件是不是一定要重新编译安装QT CREATOR呢?
如果你要开发 Qt Creator 的插件,最好自己编译一个 debug 版本的 Qt Creator,以便能够加载 debug 版本的插件用于调试(如果你编译 debug 版本的插件,就要求 Qt Creator 加载 debug 版本的 Qt 库,而安装版是 release 的,不能调试)。如果你不需要调试,只能使用输出语句调试,也是可以的
hoho,多谢豆子老大,我已经成功编译QT Creator了,目前在用2.8.1版本,正在学习您的教程,我想把我做的插件so文件直接copy到别人电脑上用,最好不要把代码啥的copy来copy去,这样代码管理会比较混乱,可行么?多谢哦!
最终以二进制形式发布当然是可行的,一般是把插件复制到对应的文件夹下重启 Qt Creator 就可以找到了。为方便用户,你可以制作一个脚本自动完成复制等操作。
多谢豆子兄!
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")
是的,Qt5 的插件系统做了全新的设计,所以和 Qt4 的不兼容。
用 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
另外希望豆子修改下现有教程,能跟版本同步下。
这个错误是内存分配的问题,有可能与环境有关系?因为原来的教程也是根据网上的一篇有关 1.x 的版本来看的,所以现在一直没有更新。
你好,我的插件插入进去了,但显示"libDoNothing.so“中的插件验证数据不匹配".
在已安装插件列表中有donothing插件,但前面的状态不是对号,而是一个差号.
请问插件验证数据不匹配是什么意思,谢谢.
一般原因是插件编写错误,可能是缺少 Q_INTERFACES、Q_EXPORT_PLUGIN2 等宏。另外,当时文章是 Qt 4 的版本,注意最新版的 Qt Creator 是 Qt 5 的,可能是这里出了问题。
您好看了你的教程我是用vs编译的编译完成运行时显示“核心载入失败,无法加载D:\QT\Qtcreator\build\lib\qtcreator\plugins\core.dll库,找不到指定的模块”但是我这个目录下面是有这个模块的
会不会是这个路径不在运行时的环境里面?所以找不到?
你好,我按照老师你的步骤操作,提示src/plugins/coreplugin/coreplugin.pri这个文件,有coreplugin.pro!
几个QtCreator版本的源码我都下载了,还是没找到,请问这是什么原因呢?
可能是版本架构又有调整吧,新版本可以看看帮助文档,帮助里面现在已经有了关于 Qt Creator 插件的相关内容,可以参考下。
请教楼主 相比于QT自带l的Plugin ,l工程中是否用CTK Plugin Framework更多一些?
这个还是看项目需求吧,个人感觉如果官方的功能能够满足,尽量以官方的为主,毕竟社区的框架不能保证以后是否还会维护。