如何创建 Qt 插件?

如何创建 Qt 插件?

简单三部曲

  1. 定义接口类或接口基类并使用 Q_DECLARE_INTERFACE 宏进行声明
  2. 所有的插件都需要继承该基类并继承 QObject(不带界面插件) or QWidget(带界面插件)
  3. 在插件类中添加 Q_PLUGIN_METADATA 导出元数据,使用 Q_INTERFACES 指定继承基类(该基类需要使用 Q_DECLARE_INTERFACE 声明过)

如何生成?

示例
*.pro 文件内容如下

# 插件依赖模块
QT       += core gui widgets

# 生成目标文件名称
TARGET = FlowWidget
TEMPLATE = lib
CONFIG += plugin

# 插件输出目录
DESTDIR = $$[QT_INSTALL_PLUGINS]/generic

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
        flowWidget.cpp

HEADERS += \
        flowWidget.h

DISTFILES += FlowWidget.json 

include($$PWD/interface/interface.pri)

interface.pri 内容如下:

SOURCES += \

HEADERS += \
    $$PWD/flowInterface.h

INCLUDEPATH += $$PWD

纯接口类定义如下:

#include <QtPlugin>
class QImage;
class QString;
class QWidget;
class FlowInterface
{
public:
    FlowInterface() {}
    virtual ~FlowInterface() {}
    virtual void process() = 0;
    /*!
        属性页
    */
    virtual QWidget *propertyPage() = 0;
};

#define FlowInterface_iid "com.xiongwei.cheung.FlowInterface"

Q_DECLARE_INTERFACE(FlowInterface, FlowInterface_iid)

注意:在插件类中我们需要实现接口中定义的纯虚函数

插件定义分为带界面和不带界面两种,采用多重继承的方式分别继承 QWidget 或 QObject 即可.

  1. 带界面插件定义如下:
class FlowWidget : public QWidget , FlowInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "com.xiongwei.cheung.FlowWidget" FILE "FlowWidget.json")
    Q_INTERFACES(FlowInterface)
public:
    explicit FlowWidget(QWidget *parent = nullptr);
    void process();
    QWidget *propertyPage();
signals:

public slots:

private:

};

FlowWidget::FlowWidget(QWidget *parent) : QWidget(parent)
{

}

void FlowWidget::process()
{
    // to do something
}

QWidget *FlowWidget::propertyPage()
{
    return this;
}

FlowWidget.json 文件是可选的,可通过该文件实现密钥插件

{
    "Keys" : [ "FlowWidget" ]
}
  1. 不带界面插件定义如下:
class FlowObject : public QObject , FlowInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "com.xiongwei.cheung.FlowObject")
    Q_INTERFACES(FlowInterface)
public:
    explicit FlowObject(QObject *parent = nullptr);
    void process();
    QWidget *propertyPage();
signals:

public slots:

private:

};

FlowObject::FlowObject(QObject *parent) : QObject(parent)
{

}

void FlowObject::process()
{
    // to do something
}

QWidget *FlowObject::propertyPage()
{
    return nullptr;
}

如何使用?

main.cpp 文件中添加插件加载路径

QCoreApplication::applicationDirPath().append("\generic");

在工程文件中包含插件接口基类文件 flowInterface.h

#include <QPluginLoader>
#include "flowInterface.h"

void load()
{
    // 添加一个枚举目录所有动态库文件即可加载所有插件
    QPluginLoader pluginLoader("FlowWidget.dll");
    // 打印插件元数据,即 json 文件内容中的键值数据
    qDebug() << pluginLoader.metaData();
    // 加载该插件
    QObject *plugin = pluginLoader.instance();
    if (plugin) {
        // 转换成接口基类指针
        FlowInterface *p  = qobject_cast<FlowInterface *>(plugin);
        if (p){
            // 显示界面
            p->propertyPage()->show();
        }

    }
}

注意一个插件类中只能存在一个 Q_PLUGIN_METADATA 宏,使用该宏会导出 qt_plugin_instanceqt_plugin_query_metadata 俩个函数。
显然如果使用 2 次 Q_PLUGIN_METADATA 宏会导致函数重定义.

实际上如果向导出多个插件的可以使用 QGenericPlugin 的手法根据 keys and `` 创建不同的对象.

posted @ 2019-11-28 14:29  學海無涯  阅读(685)  评论(0编辑  收藏  举报