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插件。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM