前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Qt插件创建及加载

Qt插件创建及加载

作者头像
用户5908113
发布2019-12-19 14:58:03
1.7K0
发布2019-12-19 14:58:03
举报
文章被收录于专栏:Pou光明Pou光明

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

上次我们是直接在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 。

代码语言:javascript
复制
#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)

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

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)

代码语言:javascript
复制
QWidget *MyFirstPlugin::createPluginWidget(QWidget *parent)
{
    PluginWidget *pluginWidget = new PluginWidget(parent);
    return pluginWidget;
}

PluginWidget是插件逻辑实现的子工程,该工程中我仅在UI中添加了两个label。

至此,插件编写完成。

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

4. 宿主程序加载插件

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

宿主程序中有一个AbstractInterface对象

遍历PluginWidget目录下的文件,如果实例化成功则使用qobject_cast()测试插件是否实现了给定的接口。【应用程序扩展插件步骤的③和④】

代码语言:javascript
复制
 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)和一个测试按钮。最后效果如下:

总结:

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

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

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Pou光明 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档