【Qt之·Qt插件开发·(3)插件之间相互通信】

系列文章目录

第一章 Qt插件创建并调用插件
第二章 Qt创建插件管理器统一管理插件
第三章 Qt插件之间相互通信
第四章 Qt创建并加载一个窗口插件
第五章 Qt插件工程作为子工程



前言


一、创建插件

  插件的通信通过插件管理器来管理,插件管理器转发插件的消息。在插件基类中,加入通信结构体,加入插件发送消息和接收消息的纯虚函数。

1.插件的接口类的定义

#include<QtPlugin>
#include<QJsonObject>

struct PluginMetaData{
    QString src;
    QString dest;
    QString msg;

    QObject *object = nullptr;
    QJsonObject info = QJsonObject();
};

Q_DECLARE_METATYPE(PluginMetaData);

class PluginInterface
{
public:
    virtual ~PluginInterface() {}
    virtual QString getName() const = 0;
    virtual QString showText() const = 0;
    virtual void recMsgFromManager(PluginMetaData) = 0;
    virtual void sendMsgManager(PluginMetaData) = 0;
};

Q_DECLARE_INTERFACE(PluginInterface,"org.galaxyworld.plugins.PluginInterface/1.0")

Q_DECLARE_METATYPE(type)

该宏用于声明自定义类型以便能够在信号槽机制中使用。需要将自定义类型作为参数传递给该宏,在运行时才能正确处理相应类型的信号与槽连接。这个宏让QOject及其子类知道这个类型。

Q_DECLARE_INTERFACE(ClassName, Identifier)

该宏将标识符(字符串)与名为 ClassName 的接口类相关联。标识符必须是唯一的。
Q_DECLARE_INTERFACE 不能在命名空间内。

2.插件01

#include "Plugin01_global.h"
#include<QObject>
#include"PluginInterface.h"
#include<QDebug>

class PLUGIN01_EXPORT Plugin01 : public QObject , PluginInterface
{
    Q_OBJECT
    Q_INTERFACES(PluginInterface)
    Q_PLUGIN_METADATA(IID "plugin01")
public:
    Plugin01();
    virtual QString getName() const override
    {
        return "Plugin01";
    }

    virtual QString showText() const override
    {
        return "this is Plugin01";
    }

    virtual void recMsgFromManager(PluginMetaData metaData) override
    {
        qDebug() << "插件Plugin01接收到消息:" << metaData.msg;
    }

signals:
    virtual void sendMsgManager(PluginMetaData)override;
};

3.插件02

#include "Plugin02_global.h"
#include<QObject>
#include"PluginInterface.h"
#include<QDebug>

class PLUGIN02_EXPORT Plugin02 : public QObject , PluginInterface
{
    Q_OBJECT
    Q_INTERFACES(PluginInterface)
    Q_PLUGIN_METADATA(IID "plugin02")
public:
    Plugin02();
    virtual QString getName() const override
    {
        return "Plugin02";
    }

    virtual QString showText() const override
    {
        return "this is Plugin02";
    }

    virtual void recMsgFromManager(PluginMetaData metaData) override
    {
        qDebug() << "插件Plugin02接收到消息:" << metaData.msg;
    }

signals:
    virtual void sendMsgManager(PluginMetaData)override;

Q_INTERFACES(…)

该宏用于在具体的实现类中声明所支持的接口。将要实现的接口类型作为参数传递给该宏即可。

Q_PLUGIN_METADATA(...)

此宏用于声明插件对象的元数据(元数据是场景对象的一部分)。
宏需要声明通过对象实现的接口的 IID,并引用包含插件元数据的文件。这个宏应该只在 Qt 插件的源代码中出现一次。使用此宏的类必须是可默认构造的。FILE 是可选的,指向一个 json 文件。json 文件必须驻留在构建系统指定的包含目录之中。 当 moc 找不到指定的文件时,它会以错误退出。

二、插件管理器

1.定义插件管理器

class PluginManger : public QObject
{
    Q_OBJECT

public:

    static PluginManger *instance()
    {
        if(nullptr == m_instance)
        {
            m_instance = new PluginManger;
        }
        return m_instance;
    }

    void loadAllPlugins();
    void unloadAllPlugins();
    void loadPlugin(const QString &filePath);
    void unloadPlugin(const QString &filePath);
    QPluginLoader *getPlugin(const QString &name);
    QVariant getPluginName(QPluginLoader *loader);

public slots:
    void recMsgFromManager(PluginMetaData metadata);

private:
    explicit PluginManger(QObject *parent = nullptr);
    ~PluginManger();

    QHash<QString,QPluginLoader *> loaders;
    QHash<QString,QString> names;

    static PluginManger *m_instance;

    class GarbageCollector
    {
        ~GarbageCollector()
        {
            if(PluginManger::instance())
            {
                delete  PluginManger::instance();
                PluginManger::m_instance = nullptr;
            }
        }
    };

    static GarbageCollector gc;

2.定义插件管理器中声明的函数

void PluginManger::loadAllPlugins()
{
    QDir pluginsdir(QDir::currentPath());
    qDebug() << QDir::currentPath();
    pluginsdir.cd("..\\Lib");

    QFileInfoList pluginsInfo = pluginsdir.entryInfoList(\
                QDir::Files | QDir::NoDotAndDotDot);

    for(QFileInfo fileInfo : pluginsInfo)
            loadPlugin(fileInfo.absoluteFilePath());
}

void PluginManger::unloadAllPlugins()
{
    for(QString filePath : loaders.keys())
        unloadPlugin(filePath);
}

void PluginManger::loadPlugin(const QString &filePath)
{
    if(!QLibrary::isLibrary(filePath))
        return;

    QPluginLoader *loader = new QPluginLoader(filePath);
    QString pluginName;
    if(loader->load())
    {
        PluginInterface *plugin = qobject_cast<PluginInterface *>(loader->instance());
        if(plugin)
        {
            pluginName = plugin->getName();
            loaders.insert(filePath,loader);
            names.insert(filePath,pluginName);
            qDebug() << "插件名称:" << plugin->getName() << "插件信息" << plugin->showText();
            
/*****************************************************************************************************************************/
            connect(loader->instance(),SIGNAL(sendMsgManager(PluginMetaData)),this,SLOT(recMsgFromManager(PluginMetaData)));
/*****************************************************************************************************************************/

        }else {
            delete loader;
            loader = nullptr;

        }

    }else {
        qDebug() << "loadPlugin:" << filePath << loader->errorString();
    }
}

void PluginManger::unloadPlugin(const QString &filePath)
{

    QPluginLoader *loader = loaders.value(filePath);
    if(loader->unload())
    {
        loaders.remove(filePath);
        delete loader;
        loader = nullptr;
    }
}

QPluginLoader *PluginManger::getPlugin(const QString &name)
{
    return loaders.value(names.key(name));
}

QVariant PluginManger::getPluginName(QPluginLoader *loader)
{
    if(loader)
        return names.value(loaders.key(loader));
    else {
        return  "";
    }
}

void PluginManger::recMsgFromManager(PluginMetaData metadata)
{
    auto loader = getPlugin(metadata.dest);
    if(loader)
    {
        auto interface = qobject_cast<PluginInterface *>(loader->instance());
        if(interface)
        {
            interface->recMsgFromManager(metadata);
        }
    }
}

三、插件通过插件管理器进行相互通信

PluginManger *pm = PluginManger::instance();
    auto loader = pm->getPlugin("Plugin01");

    if(loader)
    {
        PluginInterface *plugin = qobject_cast<PluginInterface *>(loader->instance());
        PluginMetaData m;
        m.dest = "Plugin02";
        m.src = "Plugin01";
        m.msg = "插件1给插件2发的消息~~~";
        emit plugin->sendMsgManager(m);
    }else {
        qDebug() << "插件不存在";
    }

通信过程本质: 父类调用子类的方法。


总结

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值