14

Qt插件创建及加载

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzUxMTk4MzY3MA%3D%3D&%3Bmid=2247484186&%3Bidx=1&%3Bsn=deca1f24bd81ee8920f2c5c2a06199dd
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

点击上方蓝字可直接关注公众号,方便下次阅读。

在开展新内容前,先简单回顾下上篇文章的内容。

上次我们是直接在Qt 自带的例子基础上做的修改,直接运行。我们的插件需要继承 QtStyle 插件,之后重新实现自己想要实现的部分。在主程序中直接通过 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

BzyUveR.png!web

创建完成后工程是空的,选中工程后鼠标右键,【New SubProject...】,如图。之后添加的子工程就像平时创建带有 UI 的工程一样,我选择的是继承 QWidget

ZVrIZjr.png!web

此时编译运行的话会显示一个为空的QWidget窗体。创建成功后大概向下面的样子

fuMjYja.png!web

2.  通过插件使应用程序可 以被扩展

【应用程序扩展插件步骤】

①编写仅具有纯虚函数的类

选中文件夹 Headers 后右键,选择【 Add New... 】,选择【 C++ Header File 】,我的名称是 abstractinterface.h 。由于我想创建的插件是带有 UI 的,所以类型是 QWidget

#include <QObject>

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)

此时通过插件使应用程序可以被扩展的前两步就完成了,后面两步之后在宿主程序中加载插件时再介绍。此时你的工程看起来是这个样子:

zaaYfqq.jpg!web

3. 再添加一个子工程用于编写插件

①再次添加一个子工程

选中工程【MyFirstPlugin】后鼠标右键,【 New SubProject... 】。之后添加的子工程就像平时创建带有 UI 的工程一样,我选择的是继承 QWidget 。我的名称是PluginWidget

②修改 PluginWidget

新创建的PluginWidget包含有 main.cpp ,将它删除。

修改PluginWidget.peo,将 TEMPLATE = app 改为 TEMPLATE = lib ;添加CONFIG   += plugin

【插件编写步骤】  

③声明一个插件类,该类继承自QObject 和该插件要提供的接口

之后添加一个继承QObject的类,我的名称是 MyFirstPlugin 。该类就是插件类。

此时你的工程看起来是这个样子:

yYFNnqq.jpg!web

这步还没结束,还要再继承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

至此,插件编写完成。

NzYR7fA.jpg!web

此时运行工程会生成一个插件,如图:

JfMnQzJ.png!web

4. 宿主程序加载插件

①在应用程序中使用QPluginLoader() 加载插件

宿主程序中有一个AbstractInterface对象

mQfAvqr.jpg!web

遍历 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<AbstractInterface *>(plugin);

if(m_pluginInterface)

{

m_pluginInterface->createPluginWidget(ui->pluginWidget);

ok = true;

}

}

}

在主 UI 中添加了一个 Widget( ui->pluginWidget ) 和一个测试按钮。最后效果如下:

QnAfuan.png!web

总结:

插件创建完以及加载后,整个流程就像官网描述的一样。对没有基础的同志来讲还是有一定难度,所以我就又自己搭建了一遍。

过程中涉及到了Qt的子工程、 qmake 的使用等。

Qt的插件从 C++ 的角度来讲就是 C++ 纯虚函数的应用,需要规定接口,由插件去实现,宿主程序只负责调用。

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

auiQjuN.png!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK