QT Plugin 热拔插插件

        QT中 热加载插件 和动态加载DLL有什么区别 ?热加载插件是在程序运行时动态加载插件,而动态加载DLL是在程序编译时就将DLL文件链接到程序中。热加载插件可以在不停止程序的情况下更新插件,而动态加载DLL需要重新编译程序才能更新DLL文件。

        QT 中 热加载插件如何在不停止程序的情况下更新插件?使用 QPluginLoader 类来实现热加载插件。在程序运行时,使用 QPluginLoader 加载插件,并使用 QObject::connect() 函数连接插件的信号和槽。当需要更新插件时,可以使用 QPluginLoader::unload() 函数卸载旧插件,然后再次使用 QPluginLoader 加载新插件即可。这样就可以在不停止程序的情况下更新插件。

        个人理解在实际项目中使用DLL动态库的时候,如果需要更新或者进行替换的时候需要关闭程序替换DLL在重启程序,一般可能没什么但是有些特殊场景需要24小时工作或者有通信、一直有任务在运行不适合关闭主程序,这种情况则非常需要 QT Plugin 热拔插插件 功能,无需重启程序在设置界面加个设置按钮和连接一个信号槽就可以实现动态不停止程序的情况下更新插件。

 本文作者原创,转载请附上文章出处与本文链接。

QT Plugin 热拔插插件目录

1 QPluginA

1.1 QPluginA.pro

1.2 DeclareInterface.h

1.3 qplugina.h

1.4 qplugina.cpp

2 QPluginB

2.1 QPluginB.pro

2.2 DeclareInterface.h

2.3 qpluginb.h

2.4 qpluginb.cpp

3 QMainPlugin

3.1 QMainPlugin.pro

3.2 DeclareInterface.h

3.3 mainwindow.h

3.4 mainwindow.cpp


1 QPluginA

        插件A源代码

1.1 QPluginA.pro

QT += core
QT += gui
QT             += widgets


TEMPLATE = lib
CONFIG += plugin
TARGET = HelloCTK


CONFIG += c++11


EXAMPLE_FILES = qtplugin.json




greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    qplugina.cpp

HEADERS += \
    DeclareInterface.h \
    QPluginA_global.h \
    qplugina.h

# Default rules for deployment.
unix {
    target.path = /usr/lib
}
!isEmpty(target.path): INSTALLS += target

1.2 DeclareInterface.h

//declareinterface.h
#ifndef DECLAREINTERFACE_H
#define DECLAREINTERFACE_H


#include <QWidget>

//定义接口
class DeclareInterface
{
public:
    virtual ~DeclareInterface() {}
    virtual int add(int a,int b) = 0;
};

//一定是唯一的标识符
#define DeclareInterface_iid "Examples.Plugin.DeclareInterface"

QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(DeclareInterface, DeclareInterface_iid)
QT_END_NAMESPACE

#endif // DECLAREINTERFACE_H

1.3 qplugina.h

#ifndef QPLUGINA_H
#define QPLUGINA_H

#include "QPluginA_global.h"
#include <QObject>
#include <QtPlugin>
#include "DeclareInterface.h"

class  QPluginA : public QObject, public DeclareInterface
{
    Q_OBJECT
    Q_INTERFACES(DeclareInterface)
    Q_PLUGIN_METADATA(IID  "qtplugin.json")


public:

    QPluginA(QObject *parent = 0);
    int add(int a, int b);


};

#endif // QPLUGINA_H

1.4 qplugina.cpp

#include "qplugina.h"

QPluginA::QPluginA(QObject *parent) : QObject(parent)
{
}

int QPluginA::add(int a, int b)
{
    return a+b;
}

2 QPluginB

        插件B源代码

2.1 QPluginB.pro

QT += core
QT += gui
QT             += widgets


TEMPLATE = lib
CONFIG += plugin
TARGET = HelloCTKS


CONFIG += c++11


EXAMPLE_FILES = qtplugin.json
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    qpluginb.cpp

HEADERS += \
    DeclareInterface.h \
    QPluginB_global.h \
    qpluginb.h

# Default rules for deployment.
unix {
    target.path = /usr/lib
}
!isEmpty(target.path): INSTALLS += target

2.2 DeclareInterface.h

//declareinterface.h
#ifndef DECLAREINTERFACE_H
#define DECLAREINTERFACE_H


#include <QWidget>

//定义接口
class DeclareInterface
{
public:
    virtual ~DeclareInterface() {}
    virtual int add(int a,int b) = 0;
};

//一定是唯一的标识符
#define DeclareInterface_iid "Examples.Plugin.DeclareInterface"

QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(DeclareInterface, DeclareInterface_iid)
QT_END_NAMESPACE

#endif // DECLAREINTERFACE_H

2.3 qpluginb.h

#ifndef QPLUGINB_H
#define QPLUGINB_H

#include "QPluginB_global.h"
#include <QObject>
#include <QtPlugin>
#include "DeclareInterface.h"

class  QPluginB : public QObject, public DeclareInterface
{
public:
    Q_OBJECT
    Q_INTERFACES(DeclareInterface)
    Q_PLUGIN_METADATA(IID  "qtplugin.json")


public:

    QPluginB(QObject *parent = 0);
    int add(int a, int b);
};

#endif // QPLUGINB_H

2.4 qpluginb.cpp

#include "qpluginb.h"

QPluginB::QPluginB(QObject *parent) : QObject(parent)
{
}

int QPluginB::add(int a, int b)
{
    return a-b;
}

3 QMainPlugin

        项目源代码

3.1 QMainPlugin.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    DeclareInterface.h \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

3.2 DeclareInterface.h

//declareinterface.h
#ifndef DECLAREINTERFACE_H
#define DECLAREINTERFACE_H


#include <QWidget>

//定义接口
class DeclareInterface
{
public:
    virtual ~DeclareInterface() {}
    virtual int add(int a,int b) = 0;
};

//一定是唯一的标识符
#define DeclareInterface_iid "Examples.Plugin.DeclareInterface"

QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(DeclareInterface, DeclareInterface_iid)
QT_END_NAMESPACE

#endif // DECLAREINTERFACE_H

3.3 mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include <QDir>
#include <QDebug>
#include <QMessageBox>
#include <QPluginLoader>

#include "DeclareInterface.h"

#pragma execution_character_set("utf-8")
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    void on_pushButton_3_clicked();

private:
    Ui::MainWindow *ui;

    QPluginLoader pluginLoader;

    bool loadPlugin(QString strPlugin);   //加载插件
    DeclareInterface* m_pInterface = nullptr;  //获取插件类型
};
#endif // MAINWINDOW_H

3.4 mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);



}

MainWindow::~MainWindow()
{
    delete ui;
}

bool MainWindow::loadPlugin(QString strPlugin){

    pluginLoader.setFileName(strPlugin);
    QObject *plugin = pluginLoader.instance();
    qDebug() << __FUNCTION__ << pluginLoader.errorString();
    if (plugin) {
        m_pInterface = qobject_cast<DeclareInterface *>(plugin);
        if (m_pInterface)
            return true;
    }
    return false;
}


void MainWindow::on_pushButton_clicked()
{
    int a = 5;
    int b = 5;
    int r = -1;
    if(m_pInterface){
        r = m_pInterface->add(a, b);
    }
    QMessageBox::warning(this, "插件调用成功", QString::number(r));

}

void MainWindow::on_pushButton_2_clicked()
{
    pluginLoader.unload();
    if(!loadPlugin("HelloCTK.dll")){
        QMessageBox::warning(this, "Error", "Could not load the plugin");
    }

}

void MainWindow::on_pushButton_3_clicked()
{
    pluginLoader.unload();
    if(!loadPlugin("HelloCTKS.dll")){
        QMessageBox::warning(this, "Error", "Could not load the plugin");
    }
}

PS: 程序效果图  PluginA 实现了减法 PluginB实现了加法

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Qt是一款跨平台的C++应用程序开发框架,支持各种GUI(图形用户界面)和非GUI应用程序开发Qt提供了插件Plugin)机制,使开发者可以将应用程序的功能模块化,以实现灵活的插件开发Qt插件机制允许开发者将应用程序的一部分功能独立封装成插件,并在运行时动态加载。这样的好处是插件可以在不重新编译整个应用程序的情况下进行更新或替换,极大地提升了开发效率和灵活性。 插件开发中,Qt提供了一些关键的类和接口,包括QPluginLoader、QObject和Q_EXPORT_PLUGIN2等。首先,使用QPluginLoader类可以在运行时加载插件,并提供了查找和实例化插件的功能。其次,插件类需要派生自QObject类,并通过宏Q_OBJECT和Q_PLUGIN_METADATA来声明,以便Qt能够正确处理插件的元数据和信号槽机制。最后,Q_EXPORT_PLUGIN2宏用于导出插件类的实例,使其可以被QPluginLoader动态加载。 利用Qt插件机制,开发者可以将应用程序按功能划分为不同的插件模块,简化开发过程和项目维护。插件可以通过简单的配置文件进行注册和管理,实现插件的自动加载和卸载。另外,Qt的信号槽机制可以在插件之间进行通信和交互。这使得多个独立开发插件可以灵活地协同工作,提供更丰富的功能和扩展性。 总结来说,Qt插件机制使得应用程序的功能模块化,提供了灵活的插件开发方式。开发者可以通过动态加载和卸载插件,实现插件的更新和替换,提升开发效率和项目的可维护性。插件之间可以通过信号槽机制进行通信和交互,实现更丰富的功能和扩展性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

双子座断点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值