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++
纯虚函数的应用,需要规定接口,由插件去实现,宿主程序只负责调用。

最后,如需整体工程的同志可在公众号后台留言: