Qt插件创建及加载
点击上方蓝字可直接关注公众号,方便下次阅读。
在开展新内容前,先简单回顾下上篇文章的内容。
上次我们是直接在Qt 自带的例子基础上做的修改,直接运行。我们的插件需要继承 Qt
的 Style
插件,之后重新实现自己想要实现的部分。在主程序中直接通过 QApplication::setStyle
进行调用。
下面开展我们本次的内容,官方文档说明
通过插件不仅可以扩展Qt本身,而且可以扩展 Qt
应用程序。
这要求应用程序使用QPluginLoader
检测和加载插件。 在这种情况下,插件可以提供任意功能,并且不仅限于数据库驱动程序,图像格式,文本编解码器,样式以及扩展
Qt 功能的其他类型的插件。
1. 通过插件使应用程序可扩展涉及以下步骤:
①定义一组用于与插件对话的接口(仅具有纯虚函数的类)。
②使用Q_DECLARE_INTERFACE
()
宏向
Qt 的元对象系统
声明该接口。
③在应用程序中使用 QPluginLoader
加载插件。
④
使用
qobject_cast
()测试插件是否实现了给定的接口。
2. 编写一个插件的步骤:
①声明一个插件类,该类继承自QObject
和该插件要提供的接口。
②使用Q_INTERFACES
()
宏告诉
Qt 的元对象系统
有关接口的信息。
③使用Q_PLUGIN_METADATA
()宏导出插件。
④
使用合适的
.pro 文件构建插件。
上面的步骤看不大懂?没关系,下面我们通过程序来逐步分解上面的步骤
1. 创建子工程
Qt 应用程序
在Qt新建工程时,选择创建子工程,如下图。
按照提示完成子工程的创建,我的工程名称是MyFirstPlugin
创建完成后工程是空的,选中工程后鼠标右键,【New SubProject…】,如图。之后添加的子工程就像平时创建带有 UI
的工程一样,我选择的是继承 QWidget
。
此时编译运行的话会显示一个为空的QWidget窗体。创建成功后大概向下面的样子
2. 通过插件使应用程序可
以被扩展
【应用程序扩展插件步骤】
①编写仅具有纯虚函数的类
选中文件夹
Headers 后右键,选择【
Add New…
】,选择【
C++ Header File
】,我的名称是
abstractinterface.h
。由于我想创建的插件是带有
UI 的,所以类型是
QWidget
。
#include class QWidget; class AbstractInterface { public: virtual ~AbstractInterface() {} virtual QWidget *createPluginWidget(QWidget *parent) = 0; };
【应用程序扩展插件步骤】
②使用 Q_DECLARE_INTERFACE
()
宏向
Qt 的元对象系统
声明该接口。
里面字符串内容是声明一个独一无二的属于你的iid,我的是“欢迎关注公众号”。
#define AbstractInterface_iid “Welcome to pay attention to the public number”
Q_DECLARE_INTERFACE(AbstractInterface, AbstractInterface_iid)
此时通过插件使应用程序可以被扩展的前两步就完成了,后面两步之后在宿主程序中加载插件时再介绍。此时你的工程看起来是这个样子:
3. 再添加一个子工程用于编写插件
①再次添加一个子工程
选中工程【MyFirstPlugin】后鼠标右键,【 New SubProject…
】。之后添加的子工程就像平时创建带有 UI
的工程一样,我选择的是继承 QWidget
。我的名称是PluginWidget
②修改 PluginWidget
新创建的PluginWidget包含有 main.cpp
,将它删除。
修改PluginWidget.peo,将 TEMPLATE = app
改为 TEMPLATE = lib
;添加CONFIG += plugin
【插件编写步骤】
③声明一个插件类,该类继承自QObject
和该插件要提供的接口
之后添加一个继承QObject的类,我的名称是 MyFirstPlugin
。该类就是插件类。
此时你的工程看起来是这个样子:
这步还没结束,还要再继承AbstractInterface类,但是在 myfirstplugin.h
中无法直接包含 abstractinterface.h
,这时需要修改 PluginWidget.pro
。根据创建的目录添加 INCLUDEPATH += ../MainWidget
,这时就可以 include abstractinterface.h
了。
顺便说下,通过拆分不同的.pro也可以解耦程序,以后根据具体情况再和大家分享。
【插件编写步骤】
④使用Q_INTERFACES
()
宏告诉
Qt 的元对象系统
有关接口的信息
Q_INTERFACES(AbstractInterface)
【插件编写步骤】
⑤使用 Q_PLUGIN_METADATA
()宏导出插件
Q_PLUGIN_METADATA(IID “Welcome to pay attention to the public number.” FILE “myfirstplugin.json”)
注意下
myfirstplugin.json
,这是我们
echoplugin 中直接改名复制的,这个需要有。
echoplugin
是
Qt
自带的插件例程。
插件编写最后一步是实现
createPluginWidget(QWidget *parent)
QWidget *MyFirstPlugin::createPluginWidget(QWidget *parent) { PluginWidget *pluginWidget = new PluginWidget(parent); return pluginWidget; }
PluginWidget
是插件逻辑实现的子工程,该工程中我仅在
UI 中添加了两个
label
。
至此,插件编写完成。
此时运行工程会生成一个插件,如图:
4. 宿主程序加载插件
①在应用程序中使用QPluginLoader()
加载插件
宿主程序中有一个AbstractInterface对象
遍历
PluginWidget 目录下的文件,如果实例化成功则使用
qobject_cast
()
测试插件是否实现了给定的接口
。
【应用程序扩展插件步骤的
③和④】
foreach(QString fileName, pluginsDir.entryList(QDir::Files)) { QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName)); QObject *plugin = pluginLoader.instance();
if(plugin) { m_pluginInterface = qobject_cast(plugin); if(m_pluginInterface) { m_pluginInterface->createPluginWidget(ui->pluginWidget); ok = true; } } }
在主
UI 中添加了一个
Widget(
ui->pluginWidget
) 和一个测试按钮。最后效果如下:
总结:
插件创建完以及加载后,整个流程就像官网描述的一样。对没有基础的同志来讲还是有一定难度,所以我就又自己搭建了一遍。
过程中涉及到了Qt的子工程、 qmake
的使用等。
Qt的插件从 C++
的角度来讲就是 C++
纯虚函数的应用,需要规定接口,由插件去实现,宿主程序只负责调用。
最后,如需整体工程的同志可在公众号后台留言: