一、插件开发入门【Qt环境-mingw6.5.3-qmake版】-封装dll调用

1.先创建一个名为mainProject的主项目,并进行简单的ui布局





2.使用C++ Library库创建动态库项目作为主项目的子插件

2.1 Qt模块选择为Widgets

2.2 环境配置和主项目要一致

3.给插件添加qt界面设计类



4.给subPlugin插件添加一个名为PluginInterface.h的头文件


java 复制代码
#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H

#include <QWidget>

#define PluginInterfaceIID "com.szweebon.PluginInterface/1.0.0" // 定义一个插件接口的唯一标识符(IID),用于标识插件的接口版本

class PluginInterface{ // 这是一个纯虚基类(接口),用于定义插件接口的标准。
public:
    virtual ~PluginInterface() = default; // 虚析构函数,确保派生类在销毁时能够正确释放资源
    virtual QWidget *getWidget() = 0;   // 该函数用于返回一个 QWidget 指针,表示插件提供的界面部件
};

Q_DECLARE_INTERFACE(PluginInterface, PluginInterfaceIID) // 确保接口类和它的 IID 在 Qt 元对象系统中注册
#endif // PLUGININTERFACE_H

5.编辑subplugin.h和subplugin.cpp代码

java 复制代码
#ifndef SUBPLUGIN_H
#define SUBPLUGIN_H
#include "PluginInterface.h"
#include "subPlugin_global.h"

class SUBPLUGIN_EXPORT SubPlugin: public QObject, public PluginInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID PluginInterfaceIID)//PluginInterfaceIID就是IID
    Q_INTERFACES(PluginInterface)
public:
    SubPlugin();
    ~SubPlugin();
    QWidget *getWidget();
private:
    QWidget *mGenWidget;
};

#endif // SUBPLUGIN_H
java 复制代码
#include "subplugin.h"
#include "form.h"
SubPlugin::SubPlugin() {

    mGenWidget = Q_NULLPTR;
}

SubPlugin::~SubPlugin() {

    if(mGenWidget){
        mGenWidget->deleteLater();
    }
}
QWidget *SubPlugin::getWidget()
{
    if(!mGenWidget){
        mGenWidget = new Form;
    }
    return mGenWidget;
}

6.去掉mainProject项目和subPlugin项目的的影子编译


7.将插件subPlugin项目的PluginInterface.h赋值一份到mianProject项目中,并添加到主项目录



8.把subPlugin项目生成的dll文件复制一份到mianProject主项目

这个运行动态库项目没有exe是很正常的。反正我的没有,有dll就行

9.编写主程序代码

mainwindow.h

java 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>

#include <QPluginLoader>//插件加载类

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:
    Ui::MainWindow *ui;
    QPluginLoader  loader;
    bool isPluginLoaded;         // 标志插件是否已加载
    void removeTabWithTitle(const QString &title);
};
#endif // MAINWINDOW_H

mainwindow.cpp

java 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "PluginInterface.h"
#include <QDir>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , isPluginLoaded(false)  // 新增标志以跟踪插件是否已加载
{
    ui->setupUi(this);
    // 初始化按钮文本
    ui->pushButton->setText("加载插件");
}

MainWindow::~MainWindow()
{
    // 在销毁窗口时,检查并卸载已加载的插件
    if (isPluginLoaded) {
        loader.unload();
    }
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    if (isPluginLoaded) {
        // 如果插件已经加载,执行卸载操作
        loader.unload();
        removeTabWithTitle("插件标签");  // 清除具有特定标题的标签页
        isPluginLoaded = false;  // 更新插件加载标志
        ui->pushButton->setText("加载插件");  // 更新按钮文本
        qDebug("插件已卸载");
    } else {
        // 插件未加载时,进行加载操作
        QDir dir("D:/EmbeddedDevelopment/Qt/Plugins/mainProject/debug");
        // 如果需要使用应用程序的运行目录,可以启用以下代码
        // QDir dir(qApp->applicationDirPath());

        qDebug("目录1: %s", dir.path().toUtf8().constData());  // 输出目录路径

        // 设置插件文件路径并准备加载插件
        loader.setFileName(dir.filePath("subPlugin.dll"));
        qDebug("目录2: %s", dir.filePath("subPlugin.dll").toUtf8().constData());  // 输出插件文件路径

        // 尝试加载插件
        if (!loader.load()) {
            qDebug("Failed to load loader");
            QMessageBox::critical(this, "错误", loader.errorString());  // 显示错误信息
            return;
        }

        // 创建插件实例
        QObject *plugin = loader.instance();
        if (!plugin) {  // 如果插件实例为空,输出错误信息并退出
            qDebug("loader.instance() is null");
            return;
        }
        qDebug("插件实例创建成功");

        // 将插件实例转换为 PluginInterface 类型
        PluginInterface *pi = qobject_cast<PluginInterface *>(plugin);
        if (pi) {  // 如果转换成功,获取插件的 QWidget 并添加到 TabWidget 中
            QWidget *w = pi->getWidget();
            if (w) {
                ui->tabWidget->addTab(w, "插件标签");  // 添加插件的 QWidget 为新标签页
                qDebug("插件标签添加成功");
                isPluginLoaded = true;  // 更新插件加载标志
                ui->pushButton->setText("卸载插件");  // 更新按钮文本
            } else {
                qDebug("插件未返回有效的 QWidget");
            }
        } else {
            qDebug("插件转换失败,pi is NULL");
        }
    }
}

void MainWindow::removeTabWithTitle(const QString &title)
{
    int count = ui->tabWidget->count();
    for (int i = 0; i < count; ++i) {
        if (ui->tabWidget->tabText(i) == title) {
            ui->tabWidget->removeTab(i);
            return;  // 一旦找到并移除目标标签页后退出
        }
    }
}

10.运行结果

可以添加卸载插件界面,其实添加的是一个不能自己独立运行的封装好的动态库界面,而且项目直接没有层级,故我不建议采纳这种方法

相关推荐
先吃饱再说9 小时前
存储的进化:从 MySQL 到浏览器缓存,数据到底住在哪?
数据库
Nturmoils9 小时前
字段太多看不全,ksql 的展开模式和输出控制怎么用
数据库·后端
Databend11 小时前
Agent 轨迹分析与归因的数据工程实践
大数据·数据库·agent
这个DBA有点耶12 小时前
SQL改写进阶:标量子查询的“隐形代价”与消除实战
数据库·mysql·架构
smallyoung13 小时前
数据库乐观锁深度解析:MySQL、PostgreSQL 实战 + Spring Boot 集成指南
数据库·mysql·postgresql
parade岁月13 小时前
MySQL JOIN解析:朴实无华但食之有味
数据库·后端
用户31693538118313 小时前
MySQL服务无法启动问题解决全记录
数据库
vivo互联网技术17 小时前
从 10 分钟到 1 秒:ES 深度分页任意跳页的三轮优化实战
服务器·数据库·redis·elasticsearch·深度分页
倔强的石头_1 天前
《Kingbase护城河》——猎捕慢查询:执行计划的微观解析与索引调优实战
数据库
SelectDB1 天前
Apache Doris Python UDF:让 SQL 直接调用 Python 生态,支撑 Agent 时代复杂业务逻辑
大数据·数据库·python