QT 自定义插件及使用(QPluginLoader)

前面介绍了如何将QWidget封装成dll库并且使用,这样存在的一个问题就是 :必须要配置.pro文件,建立lib路径连接,并且需要在使用到的地方include相应的头文件。

除了在.pro中配置动态库,调用动态库的方式还有QLibrary和QPluginLoader两种。

相比于QLibrary调用动态库,QPluginloader可以将封装成动态库的界面程序实例化,而QLibrary则只能访问动态库中的函数,无法将DLL实例化,因此在使用由界面封装而来的dll时,用QPluginLoader加载动态库更为合适。

下面将详细介绍QPluginLoader库的封装及使用。

在https://www.cnblogs.com/leocc325/p/15001467.html中已经说明了如何将QWidget封装成动态库,但是通过这种方法封装出来的动态库无法被QPluginLoader加载,因此需要在原有的基础上进行一些改进。

首先还是需要创建一个接口(抽象基类)AbstractProcess,然后需要在接口中添加以下宏命令

QT_BEGIN_NAMESPACE
#define AbstractProcess_IID "org.qter.Examples.myplugin.AbstractProcess"
Q_DECLARE_INTERFACE(AbstractProcess,AbstractProcess_IID)
QT_END_NAMESPACE

红色部分是需要要添加的宏,橙色部分内容可以自定义。只有添加了这个宏之后,这个插件才能被QT识别。

整个基类头文件如下

#ifndef ABSTRACTPROCESS_H
#define ABSTRACTPROCESS_H

#include <QObject>
#include <QWidget>
#include <QJsonObject>
#include <QPaintEvent>
#include <QPainter>
#include <QStyleOption>

#if defined(ABSTRACTPROCESS_LIBRARY)
#  define ABSTRACTPROCESSSHARED_EXPORT Q_DECL_EXPORT
#else
#  define ABSTRACTPROCESSSHARED_EXPORT Q_DECL_IMPORT
#endif

class HttpConnector;
class ABSTRACTPROCESSSHARED_EXPORT AbstractProcess:public QWidget
{
    Q_OBJECT
public:
    explicit AbstractProcess(QWidget *parent = nullptr);
    virtual ~AbstractProcess();
    virtual void InitProcess() = 0;//初始化
    virtual void SetProcessParameter(QJsonObject&) = 0;//设置一些必要的参数
    virtual void PostOperateScore(HttpConnector*) = 0;//发送考核项目分数
    virtual void PostOperateLog(HttpConnector*) = 0;//发送考核项目日志
    virtual void ChangeOperateItem(int operateCode) = 0;//更换当前检定项目,跳转到对应的界面
protected:
    virtual void paintEvent(QPaintEvent *);
signals:
    void OperateIndexDone(int deviceCode,int indexCode);
    void ProcessMessage(const QString& info);//发送信息到主进程

};

//封装成插件需要在原本封装dll的基础上添加以下语句
QT_BEGIN_NAMESPACE
#define AbstractProcess_IID "org.qter.Examples.myplugin.AbstractProcess"
Q_DECLARE_INTERFACE(AbstractProcess,AbstractProcess_IID)
QT_END_NAMESPACE

#endif // ABSTRACTPROCESS_H

如上面注释内容一样,和普通的QWidget封装dll相比,仅仅需要在头文件中添加Q_DECLARE_INTERFACE()宏。

创建好接口之后,就需要继承接口创建一个可以实例化的插件dll。

在子类的头文件中需要添加以下两个宏命令

Q_PLUGIN_METADATA(IID AbstractProcess_IID)
Q_INTERFACES(AbstractProcess)

子类头文件如下

#ifndef PROCESSMULITMETER_H
#define PROCESSMULITMETER_H

#include <QWidget>
#include "abstractprocess.h"

#if defined(PROCESSMULTIMER_LIBRARY)
#  define PROCESSMULTIMERSHARED_EXPORT Q_DECL_EXPORT
#else
#  define PROCESSMULTIMERSHARED_EXPORT Q_DECL_IMPORT
#endif

namespace Ui {
class ProcessMulitmeter;
}

class  PROCESSMULTIMERSHARED_EXPORT ProcessMultimeter : public AbstractProcess
//class ProcessMultimeter : public AbstractProcess
{
    Q_OBJECT
    //和原本封装QWidget的DLL相比,需要添加以下宏命令
    Q_PLUGIN_METADATA(IID AbstractProcess_IID)
    Q_INTERFACES(AbstractProcess)

public:
    explicit ProcessMultimeter(QWidget *parent = nullptr);
    ~ProcessMultimeter();
    void InitProcess() {;}//初始化
    void SetProcessParameter(QJsonObject&) {;}//设置一些必要的参数
    void PostOperateScore(HttpConnector*) {;}//发送考核项目分数
    void PostOperateLog(HttpConnector*) {;}//发送考核项目日志
    void ChangeOperateItem(int operateCode) {Q_UNUSED(operateCode);}//更换当前检定项目,跳转到对应的界面

private:
    Ui::ProcessMulitmeter *ui;
};

#endif // PROCESSMULITMETER_H

需要注意的是,Q_PLUGIN_METADATA()宏有两个参数,第一个参数为IID,与接口的IID相同,将接口的IID复制过来就行了,第二个参数FILE是可选的,指定一个本地json文件,用于描述插件的相关数据信息。

如果没有特别的需求,第二个参数可以省略,json文件也不需要创建。

在完成编译之后,就可以看到debug文件夹中生成的dll

 

 

 如果是插件的话只需要将dll复制到需要使用的工程目录中,和exe同级。不需要添加头文件和lib,也不需要在.pro中进行配置,以及#include

比调用动态库方便太多。

之后就可以在程序中用QPluginLoader加载这个库

 QPluginLoader loader("ProcessMultimeterD.dll");
    if(loader.load())
    {
        if(QObject * plugin = loader.instance())
        {
            process = dynamic_cast<AbstractProcess *>(plugin);
            qDebug()<<process;
            process->setParent(ui->ExamStackedWidget->widget(1));
        }
    }
    else
    {
        qDebug()<<loader.errorString();
    }

因为我这里dll和exe在同一级文件夹中,因此不需要在前面添加文件路径什么的,直接将dll名字作为Loader参数就可以找到这个插件。

这里的process是一个AbstractProcess指针,要创建dll的实例化对象,依然需要包含接口的头文件,lib和dll,子类的只需要包含dll。

程序运行之后

 

 

 就可以看到中间空白界面上出现两个仪器,这两个仪器就是刚才的dll插件。

 

posted @ 2021-08-29 14:36  lccsuse  阅读(6062)  评论(1编辑  收藏  举报