2、Qt 插件开发

插件类其实就是接口类的子类,用于实现接口类。

该Interface必须是虚基类,且所有函数(除了构造,一般也不写构造)都是虚函数。

而所谓的plugin就是继承该虚基类和QObject的子类。

当程序调用该plugin的某个函数时,是通过该plugin的虚基类在运行时动态绑定至子类的vtable执行的。

1、编写接口类

创建项目 MyPlugin1,最终用于生成插件 MyPlugin1.dll

全部默认

最终项目中,多出一个*_global.h文件,此文件不需任何更改。

添加接口类头文件 MyInterface.h

MyInterface.h

#pragma once
#include <QObject>
#include <opencv.hpp>
/**
* @brief 
* 接口类格式:
* 1、虚析构
* 2、其他函数纯虚
* 3、无成员变量
*/
class MyInterface
{
public:    //公开
    virtual ~MyInterface(){}
    virtual void medianFilter(const cv::Mat& inputImg, cv::Mat& outputImg) = 0;
};

//声明接口
#define MyInterface_IID "com.Interface.MyInterface"
Q_DECLARE_INTERFACE(MyInterface,MyInterface_IID)

2、实现接口类

myplugin1.h

#pragma once

#include "myplugin1_global.h"
#include "MyInterface.h"    //引入接口类

/**
* @brief
* 插件类其实就是接口类的子类,用于实现接口类
* 格式:
* 1、继承QObject
* 2、继承接口类
*/
class MYPLUGIN1_EXPORT MyPlugin1
    :public QObject
    ,public MyInterface
{
    //宏3联
    Q_OBJECT
    Q_PLUGIN_METADATA(IID MyInterface_IID)  //描述插件元数据
    Q_INTERFACES(MyInterface)               //本类要实现的接口
public:
    MyPlugin1();
    ~MyPlugin1();
    //实现的虚函数
    virtual void medianFilter(const cv::Mat& inputImg, cv::Mat& outputImg) override;
};

myplugin1.cpp

#include "myplugin1.h"

MyPlugin1::MyPlugin1()
{
}
MyPlugin1::~MyPlugin1()
{
}

void MyPlugin1::medianFilter(const cv::Mat& inputImg, cv::Mat& outputImg)
{
    cv::medianBlur(inputImg, outputImg, 5);
}

运行,会在Debug或Release中生成dll

3、新建程序,PluginDemo

在exe目录里新建plugins文件夹,把之前生成的插件dll放入其中。

【注意】dll是区分编译器版本、debug/release的,exe需使用对应的dll。类似VS不能用MinGW编译的dll。

把之前的接口文件放入项目路径,并添加到VS项目中

运行结果

main.cpp

#include <QtCore/QCoreApplication>
#include <QDir>
#include <QPluginLoader>

#include"MyInterface.h" //引入接口类

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //加载插件
    QDir pluginsDir = QDir(qApp->applicationDirPath()); //exe路径
    if (!pluginsDir.cd("plugins"))                      //若无法进入plugins文件夹则返回
    {
        return -1;
    }
    int counter = 0;    //统计有效插件,无则返回
    for each (QString pluginName in pluginsDir.entryList(QDir::Files))   //遍历plugins中的插件(库)
    {
        if (QLibrary::isLibrary(pluginName))           //是否是库文件
        {
            QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(pluginName));    //加载插件
            if (qobject_cast<MyInterface*>(pluginLoader.instance()))    //是否与插件接口兼容
            {
                //一些操作,如将插件展示到界面等
                //由于只是讲解插件的基本知识,此段仅参考即可。可以直接指定具体的dll进行函数调用。
                counter++;
            }
        }
    }
    if (0==counter)     //无有效插件则返回
    {
        return -1;
    }
    //直接指定具体的dll进行函数调用
    QPluginLoader pluginLoaderNow(qApp->applicationDirPath() + "/plugins/MyPlugin1.dll");   //加载插件
    MyInterface* plugin = qobject_cast<MyInterface*>(pluginLoaderNow.instance());           //实例化,接口类对象
    cv::Mat src, dst;
    src = cv::imread("C:/line.bmp");
    plugin->medianFilter(src, dst); //调用函数
    cv::imshow("原图", src);
    cv::imshow("插件里实现的中值滤波", dst);

    return a.exec();
}

 

posted @ 2022-02-23 15:25  夕西行  阅读(676)  评论(0编辑  收藏  举报