QT插件化开发详细教程

一、前言

a、什么是QT插件化开发

  • QT插件化开发是一种使用QT框架进行软件开发的方法,其中功能组件可以以插件的形式加载和使用。这种方法可以提高软件的可扩展性和灵活性,允许开发人员在不修改主程序代码的情况下动态地添加、移除或更新功能模块。QT插件通常以共享库的形式存在,可以在运行时动态加载到应用程序中。
  • 通过QT插件化开发,开发人员可以实现模块化设计,将不同功能模块拆分成独立的插件,便于管理和维护。这种方法还有助于降低软件开发的复杂性,提高代码的重用性,同时也使得软件更容易适应不断变化的需求。

b、Qt插件开发优点

Qt插件开发具有许多优点,包括:

  1. 模块化设计:插件开发允许将功能分解为独立的模块,使得代码更易于管理和维护。
  2. 可扩展性:通过插件机制,可以在不修改主应用程序的情况下轻松地添加新功能或改进现有功能。
  3. 重用性:插件可以在不同的应用程序中重复使用,提高了代码的可重用性和可移植性。
  4. 灵活性:插件可以独立开发和测试,并且可以根据需要加载或卸载,从而提供了更高的灵活性。
  5. 定制性:插件可以根据用户需求进行定制,使应用程序更加个性化和适应性更强。
  6. 性能优化:通过插件机制,可以将一些功能单独加载,从而减少应用程序的启动时间和内存占用。
  7. 社区支持:Qt拥有庞大的社区和生态系统,可以找到各种开源插件和解决方案,加速开发过程。
    总的来说,Qt插件开发提供了一种灵活、可扩展且高效的方式来扩展应用程序的功能,使得软件开发更加高效和便捷。

c、插件和动态库的差别

Qt插件和动态库(也称为共享库)在Qt框架中有不同的作用和使用方式。

  1. Qt插件:
    Qt插件是一种特定类型的动态链接库,用于扩展Qt应用程序的功能。Qt插件通常用于将特定功能模块或组件添加到应用程序中,以实现可插拔的架构设计。Qt插件可以分为不同类型,如插件接口、样式表插件、图像插件等。Qt插件通常包括插件接口的定义和实现,以及一个动态库文件,其文件名通常以特定的命名规则结尾(如插件接口为*.so或*.dll)。
  2. 动态库:
    动态库是一种包含可重用代码和功能的库文件,可以在运行时被加载到应用程序中。动态库在编译时与应用程序进行链接,但在运行时可以动态加载和卸载,以提供可扩展性和灵活性。动态库常用于共享通用功能、提供第三方库支持等场景。动态库通常以.so(Linux)、.dll(Windows)等扩展名结尾,可以通过操作系统的动态链接器来加载并运行。

总结:
Qt插件是一种特定类型的动态库,用于扩展Qt应用程序的功能,实现可插拔的架构设计;而动态库是通用的库文件,可以被应用程序动态加载和卸载,提供代码重用和可扩展性。在Qt开发中,可以根据需要选择使用Qt插件或常规动态库来扩展应用程序的功能。

d、插件的应用场景

Qt 插件通常用于扩展 Qt 框架的功能或添加额外的特性,它们可以被动态加载到 Qt 应用程序中,从而提供灵活性和可扩展性。以下是一些常见的Qt插件应用场景:

  1. UI 插件:通过创建自定义的 Qt 插件,可以实现定制的用户界面控件或部件,从而扩展 Qt 的UI组件库。这样的插件可以被轻松地添加到Qt应用程序中,以实现特定的界面设计需求。
  2. 数据处理插件:Qt 插件还可以用于处理数据,例如实现特定的数据分析算法或数据转换功能。这样的插件可以通过动态加载来提供更灵活的数据处理功能。
  3. 网络插件:通过创建网络插件,可以实现使用不同的网络协议或实现特定的网络通信功能。这些插件可以被用于实现网络相关的功能,如网络传输、远程数据访问等。
  4. 多媒体插件:Qt 提供了丰富的多媒体功能,但有时候需要一些额外的功能或格式支持。通过创建多媒体插件,可以轻松地扩展Qt的多媒体功能,以支持更多的音视频格式或实现特定的多媒体功能。
  5. 数据库插件:Qt已经内置了对一些数据库的支持,但有时候需要额外的数据库支持或者对数据库的特定功能进行定制。通过创建数据库插件,可以实现对其他数据库系统的支持或者实现特定数据库功能的扩展。
    总的来说,Qt插件可以用于几乎所有需要扩展Qt框架功能或添加新功能的场景,从而帮助开发者定制化他们的应用程序。

二、详细教程

a、创建应用程序工程

1、创建工程

在这里插入图片描述
在这里插入图片描述

2、UI文件添加内容

UI文件中添加一个textBrower和Button,实现单击按钮的时候textBrower显示插件返回的内容。
在这里插入图片描述

布局如下图所示:
在这里插入图片描述
将按钮点击槽函数转出来,
在这里插入图片描述

3、新建一个接口文件,命名为interface

在这里插入图片描述

此接口文件主要定义插件要实现的方法,是一个纯虚类,文件内容如下:

#ifndef INTERFACE_H
#define INTERFACE_H

#include <QString>
//定义接口
class Interface
{
public:
    virtual ~Interface() {}
    virtual QString getInfo() = 0;
};

//一定是唯一的标识符
#define INTERFACE_IID "my.plugin.interface"

QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(Interface, INTERFACE_IID)
QT_END_NAMESPACE


#endif // INTERFACE_H

由于是测试,只定义了一个getInfo方法。
#define INTERFACE_IID "my.plugin.interface" 定义了一个唯一的标识符,字符串一定要是唯一的。
使用 Q_DECLARE_INTERFACE() 宏来告诉 Qt 元对象系统有关接口的情况

4、实现插件加载和按钮测试相关功能

如下图所示:
在这里插入图片描述
在这里插入图片描述
其中loadPlugin函数用于加载插件。
槽函数on_pushButton_clicked()中演示了如何使用插件中的API。

mainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDir>
#include <QMessageBox>
#include <QPluginLoader>

#include "interface.h"


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();
private:
    bool loadPlugin();   //加载插件
    Interface* mInterface = nullptr;  //获取插件类型  
private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainWindow.cpp

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

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    if(!loadPlugin()){
        QMessageBox::warning(this, "Error", "Could not load the plugin");
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}
bool MainWindow::loadPlugin()
{
    QDir pluginsDir(qApp->applicationDirPath());  //pluginsDir:"../build-xxx-debug/debug"
    
    pluginsDir.cdUp();
    pluginsDir.cdUp();
    pluginsDir.cdUp();
    
    qDebug()<<"plug dir:"<<pluginsDir;
    pluginsDir.cd("plugins");
    foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
        QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
        QObject *plugin = pluginLoader.instance();
        qDebug() << __FUNCTION__ << pluginLoader.errorString();
        if (plugin) {
            this->mInterface = qobject_cast<Interface *>(plugin);
            if (mInterface)
                return true;
        }
    }
    return false;
}
void MainWindow::on_pushButton_clicked()
{
    if(mInterface){
        this->ui->textBrowser->append(mInterface->getInfo());
    }    
}


loadPlugin方法用于加载插件,插件加载后通过mInterface来调用插件中实现的方法。

b、创建插件工程

1、创建工程

在这里插入图片描述
选择Empty qmake Project
在这里插入图片描述

2、新增Plugin类

在这里插入图片描述
在这里插入图片描述

3、将Application中定义的接口文件interface拷贝过来,并添加到工程

在这里插入图片描述
在这里插入图片描述
完成后如下图所示:
在这里插入图片描述

4、在plugin中实现相关功能

在这里插入图片描述

在这里插入图片描述
主要是想纯虚函数中的getInfo功能,放回一串字符串在主应用程序中显示。

plugin.h

#ifndef PLUGIN_H
#define PLUGIN_H

#include <QObject>
#include <QtPlugin>
#include "interface.h"

class Plugin : public QObject, public Interface
{
    Q_OBJECT
    Q_INTERFACES(Interface)
    Q_PLUGIN_METADATA(IID INTERFACE_IID FILE "qtplugin.json")
public:
    explicit Plugin(QObject *parent = nullptr);
    QString printInfo();
signals:
};

#endif // PLUGIN_H

plugin.cpp

#include "plugin.h"

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

QString Plugin::printInfo()
{
    return "This is the information returned by the plugin!";
}

5、在PluginLib.pro中添加如下内容

TEMPLATE        = lib
CONFIG         += plugin
QT             += widgets

TARGET          = qtplugin
DESTDIR         = ../plugins  # 输出目录

EXAMPLE_FILES = qtplugin.json

HEADERS += \
    interface.h \
    plugin.h

SOURCES += \
    plugin.cpp

6、在插件工程目录下新增一个qtplugin.json文件内容为空

新建一个txt文件,将文件名改为qtplugin.json就可以了。
在这里插入图片描述

7、编译工程

点击编译工程,编译完成后在…/build\plugins会生成两个文件,如下图所示:
在这里插入图片描述
.a文件是静态文件,不需要,我们只使用.dll文件,所以将.a文件删除,只保留.dll文件就可以。
在这里插入图片描述

c、验证插件功能是否正常

1、将plugins文件夹拷贝到应用程序目录下

在这里插入图片描述

2、编译运行应用程序查看结果

在这里插入图片描述

三、觉得有用点个赞呗!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小灰灰搞电子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值