首页 > 其他分享 >Qt自定义插件plugin的开发和调用

Qt自定义插件plugin的开发和调用

时间:2024-09-14 12:13:15浏览次数:1  
标签:插件 Qt 自定义 int strSql QString include DbPlugin

1.需求描述

设备管理组件保存了设备信息和通道信息到sqlite数据库,其他组件也想要访问这个数据库中的内容;需要开发一个自定义插件,用于提供接口给其他组件访问数据库;

 开发环境vs2015+Qt5.9.6

2.插件介绍

插件主要面向接口编程,通过接口实现功能的扩展,而不需要访问.lib文件。插件在程序运行时即使.dll不存在,程序也能正常启动,只是相应插件功能无法正常使用。相比之下,DLL(动态链接库)需要访问.lib文件,并且在程序运行时必须保证.dll存在,否则无法正常启动。插件在调用时只需要.dll文件,不需要头文件和lib文件,这表明插件的设计更加注重于功能的动态添加和热插拔,而DLL则更侧重于提供可重用的代码和数据。

3.自定义插件实现

(1)创建一个Qt Library工程;将工程输出设置为dll;

 

(2)定义一个纯虚函数接口

#pragma once
#ifndef DbPluginInterface_H
#define DbPluginInterface_H
#include <QVariantMap>
#include <QString>
class DbPluginInterface {

public:
    virtual ~DbPluginInterface() {}
    virtual int initLocalDb(QString strDbPath)=0;
    virtual int finishLocalDb() = 0;
    /*执行SQL语句*/
    virtual int ExcuateSql(QString strSql, QVariantMap& replyData, QString& strMsg)=0;
    virtual int ExcuateSql(QString strSql, QString& strMsg)=0;
};
//声明接口,和接口id。
Q_DECLARE_INTERFACE(DbPluginInterface,"org.qter.Example.myplugin.RexExpInterface")
#endif 

(3)继承纯虚函数接口实现导出类

#ifndef DBPLUGIN_H
#define DBPLUGIN_H

#include "dbplugin_global.h"
#include <QSqlDatabase>
#include <QObject>
#include "DbPluginInterface.h"
class  DbPlugin :public QObject,public DbPluginInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qter.Example.myplugin.RexExpInterface" FILE "DbPlugin.json")
    Q_INTERFACES(DbPluginInterface)
public:
    DbPlugin();
    ~DbPlugin();
    int initLocalDb(QString strDbPath);
    int finishLocalDb();
    /*执行SQL语句*/
    int ExcuateSql(QString strSql, QVariantMap& replyData, QString& strMsg);
    int ExcuateSql(QString strSql, QString& strMsg);
private:
    QSqlDatabase db_;
};

#endif // DBPLUGIN_H

要在类定义中加入下面两行宏定义:

Q_PLUGIN_METADATA(IID "org.qter.Example.myplugin.RexExpInterface" FILE "DbPlugin.json")

Q_INTERFACES(DbPluginInterface)

Q_PLUGIN_METADATA介绍

要在类定义中加入下面两行宏定义;Q_PLUGIN_METADATA宏在 Qt 插件开发中用于声明和提供插件的元数据(metadata),使得 Qt 的插件机制能够识别并正确加载该插件。通常与 Q_OBJECT 和 Q_INTERFACES 一起使用。Q_PLUGIN_METADATA 宏将插件的信息嵌入到生成的共享库中。这个信息包含插件的标识符、版本号、描述等,可供插件加载器 (QPluginLoader) 在运行时识别和使用。这些信息也可以在插件加载前进行检索,从而允许应用程序根据插件的元数据作出决策。

Q_PLUGIN_METADATA 宏的基本语法如下:

Q_PLUGIN_METADATA(IID "插件接口标识符" FILE "元数据文件.json")
IID: 插件接口标识符,用于唯一标识插件接口。通常是一个字符串,与 Q_DECLARE_INTERFACE 中声明的标识符相对应。
FILE: 可选参数,用于指定一个包含插件元数据的 JSON 文件,内容如下。DbPlugin.json文件放到工程路径(dbplugin.cpp同目录下)下,否则编译时会报错Plugin Metadata file ".json" does not exist. 

{
    "name": "MyPlugin",
    "version": "1.0",
    "description": "This is a sample plugin for demonstration purposes.",
    "author": "Your Name",
    "license": "GPL"
}

调用者可以通过QPluginLoader 的 metaData().metaData().toVariantMap().value("MetaData") 方法获取到这个元数据,可以通过元数据的内容了解插件的信息;

QDir pluginsDir("../x64/Release/");
QPluginLoader loader(pluginsDir.absoluteFilePath("DbPlugin.dll"));
QVariantMap metadata=loader.metaData().toVariantMap();

Q_INTERFACES宏介绍

在实现插件时使用,用于指定插件实现了哪些接口,从而使运行时的Qt插件系统知晓该插件提供了哪些功能接口,并根据这些接口来调用插件的功能;与Q_DECLARE_INTERFACE宏定义配套使用,Q_DECLARE_INTERFACE在申明插件接口时使用:用于给插件接口类(ClassName)绑定一个唯一标识符(Identifier)。

(4)实现插件导出类dbpugin.cpp

#include "dbplugin.h"
#include <QCoreApplication>
#include <QFile>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlRecord>
#include<QDir>
DbPlugin::DbPlugin()
{

}

DbPlugin::~DbPlugin()
{

}

int DbPlugin::initLocalDb(QString strDbPath)
{
    int iret = -1;
    do
    {
        QString strPath = QDir::currentPath();
        db_ = QSqlDatabase::addDatabase("QSQLITE");
        QFile file(strDbPath);
        if (!file.exists())
        {
            break;
        }
        db_.setDatabaseName(strDbPath);
        if (!db_.open())
        {
            break;
        }
        iret = 0;
    } while (0);
    return iret;
}

int DbPlugin::finishLocalDb()
{
    db_.close();
    return 0;
}

int DbPlugin::ExcuateSql(QString strSql, QVariantMap& replyData, QString& strMsg)
{
    int errorCode = -1;
    QSqlQuery query;
    query.prepare(strSql);
    if (!query.exec())
    {
        QSqlError error = query.lastError();
        errorCode = error.type();
        strMsg = error.text();
        //LOG_ERROR("ExcuateSql %s failed,code:%d,errormsg:%s", strSql.toStdString().c_str(), errorCode, strMsg.toStdString().c_str());
        return -1;
    }
    QVariantList dataList;
    while (query.next())
    {
        QSqlRecord record = query.record();
        int column = record.count();

        QVariantMap data;
        for (int i = 0; i < column; i++)
        {
            data.insert(record.fieldName(i), record.value(i));
        }
        dataList.append(data);
    }
    //QVariantMap replyData;
    replyData.insert("totalCount", dataList.size());
    replyData.insert("data", dataList);
    return 0;
}

int DbPlugin::ExcuateSql(QString strSql, QString& strMsg)
{
    int errorCode = -1;
    QSqlQuery query;
    query.prepare(strSql);
    if (!query.exec())
    {
        QSqlError error = query.lastError();
        errorCode = error.type();
        strMsg = error.text();
        //LOG_ERROR("ExcuateSql %s failed,code:%d,errormsg:%s", strSql.toStdString().c_str(), errorCode, strMsg.toStdString().c_str());
        return -1;
    }
    return 0;
}

要实现数据库的加载和访问,需要配置sql模块,增加sql驱动;这样才能正确访问数据库;

 

4.调用工程如何使用插件

(1)创建一个工程,将接口文件DbPluginInterface.h复制到工程,创建数据库调用单例类,

#ifndef DBPLUGIN_H
#define DBPLUGIN_H
#include "base_define.h"
#include <QObject>
#include "DbPluginInterface.h"
class DbPlugin : public QObject,public singleton<DbPlugin>
{
    Q_OBJECT

public:
    DbPlugin();
    ~DbPlugin();
    int LoadDbPlugin();//加载插件
    /*执行SQL语句*/
     int ExcuateSql(QString strSql, QVariantMap& replyData, QString& strMsg);
     int ExcuateSql(QString strSql, QString& strMsg);
private:
    DbPluginInterface* pDbpluginInstance=NULL;
};

#endif // DBPLUGIN_H

(2)实现插件加载和接口封装,然后就可以再这个工程中调用单例类的接口,通过插件访问数据库

#include "DbPlugin.h"
#include <QPluginLoader>
#include <QDir>
DbPlugin::DbPlugin()
{

}

DbPlugin::~DbPlugin()
{

}

int DbPlugin::LoadDbPlugin()
{
    QDir pluginsDir("../x64/Release/");//指定插件的相对路径
    QPluginLoader loader(pluginsDir.absoluteFilePath("DbPlugin.dll"));///通过相对路径获取插件的绝对路径
    QObject *plugin = loader.instance();
    if (plugin) {
        pDbpluginInstance = qobject_cast<DbPluginInterface *>(plugin);
        if (pDbpluginInstance==NULL) {
            return -1;
        }
    }
    QString strDbPath = pluginsDir.absoluteFilePath("localSqliteDb.db");//sqlite和插件在同一路径,如果是其他路径,要传入数据库文件的路径,否则会报错;
    if (pDbpluginInstance->initLocalDb(strDbPath)!=0)
    {
        return -1;
    }
    return 0;
}
int DbPlugin::ExcuateSql(QString strSql, QVariantMap& replyData, QString& strMsg)
{
    if (pDbpluginInstance==NULL)
    {
        return-1;
    }
    return pDbpluginInstance->ExcuateSql(strSql, replyData, strMsg);
}
int DbPlugin::ExcuateSql(QString strSql, QString& strMsg) 
{
    if (pDbpluginInstance == NULL)
    {
        return -1;
    }
    return pDbpluginInstance->ExcuateSql(strSql, strMsg);
}

 

标签:插件,Qt,自定义,int,strSql,QString,include,DbPlugin
From: https://www.cnblogs.com/bclshuai/p/18413502

相关文章

  • PbootCMS留言自定义表单怎么调用
    在PBootCMS中,你可以通过自定义表单和标签来实现留言功能。以下是详细的步骤和示例代码,帮助你在全站任意地方使用留言表单和留言记录列表。1.留言提交表单示例代码<formaction="{pboot:msgaction}"method="post">联系人:<inputtype="text"name="contacts"require......
  • qt和西门子plc的通讯,用的snap7协议
    个人日记,主要通过s7协议进行pc和设备的连接,知道plc(我用的smart200)的地址,端口号默认102,然后通过协议里的函数进行读取数据,然后在自己编写一个数据处理的过程,得到最终的结果。出现问题:无法连接,看电脑是否与plc的地址在同一网段,win+r cmd进行去pingplc的地址,来确认是否能pi......
  • QT6 QML编程
    QT6QML编程使用AI技术辅助生成QT界面美化视频课程QT性能优化视频课程QT原理与源码分析视频课程QTQMLC++扩展开发视频课程免费QT视频课程您可以看免费1000+个QT技术视频免费QT视频课程QT统计图和QT数据可视化视频免费看免费QT视频课程QT性能优化视频免费看免费QT视......
  • QT6跨平台开发
    QT6跨平台开发使用AI技术辅助生成QT界面美化视频课程QT性能优化视频课程QT原理与源码分析视频课程QTQMLC++扩展开发视频课程免费QT视频课程您可以看免费1000+个QT技术视频免费QT视频课程QT统计图和QT数据可视化视频免费看免费QT视频课程QT性能优化视频免费看免费QT......
  • PyQt5--打造精美、功能强大的桌面应用程序
    ui文件转换为python文件方法一:直接使用命令行转换,demo.ui为保存的ui名,demo.py为ui转换为python的文件。1python-mPyQt5.uic.pyuicdemo.ui-odemo.py QLabel案例:使用信号以下是QLabel控件的常用信号:linkActivated:当控件中包含超链接时,用户单击链接时触发此信号。......
  • 自定义穿梭框封装
      后面有时间再来慢慢搞吧,暂且先这样,有需要的可以把代码考过去继续弄<template><divid="app"><divclass="f-transferflex"><!--left--><divclass="f-left"><divclass="f-topflexflex-jus......
  • 自定义WPF滑块样式-Slider
    在Windows应用程序开发中,滑块(Slider)是一个非常常见且有用的控件。它可以让用户通过拖动滑块来选择一个范围内的值。然而,WPF或UWP应用程序中的默认滑块样式可能并不总是符合我们的设计需求。因此,我们需要自定义滑块的样式。在本文中,我将向你展示如何使用XAML(ExtensibleApplicat......
  • QT6 QML编程
    QT6QML编程使用AI技术辅助生成[QT界面美化视频课程](https://edu.csdn.net/lecturer/7637)[QT性能优化视频课程](https://edu.csdn.net/lecturer/7637)[QT原理与源码分析视频课程](https://edu.csdn.net/lecturer/7637)[QTQMLC++扩展开发视频课程](https://edu.csdn.net/lectu......
  • Qt 实战(10)模型视图 | 10.3、模型数据索引
    文章目录一、模型数据索引1、什么是模型数据索引?2、模型3、获取`QModelndex`3.1、获取列表数据项索引3.2、获取表格数据项索引3.3、获取树数据项索引4、模型数据更新前言:在Qt框架中,模型/视图(Model/View)架构是一种强大的机制,它允许开发者将数据的存储(Model)与数据......
  • modbus调试助手/mqtt调试工具/超轻巧物联网组件/多线程实时采集/各种协议支持
    一、前言说明搞物联网开发很多年,用的最多的当属modbus协议,一个稳定好用的物联网组件是物联网平台持续运行多年的基石,所以这个物联网组件从一开始就定位于自研,为了满足各种场景的需求,当然最重要的一点就是大大提升了自己对该协议的深度理解和应用,尤其是面对各种场景需求,逐步调整迭......