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

news/2024/9/20 7:14:45/文章来源:https://www.cnblogs.com/bclshuai/p/18413502

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_OBJECTQ_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_OBJECTpublic: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);
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/796956.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SCM信道模型和SCME信道模型的matlab特性仿真,对比空间相关性,时间相关性,频率相关性

1.算法仿真效果 matlab2022a仿真结果如下(完整代码运行后无水印): 由仿真结果可以看出:信道时间相关性随着时间间隔的增大而减小,同一个天线间隔下,宏小区与微小区的间相关性相同,因为这两种场景的AOA产生方法相同,也反映出该信道模型不够准确。同理,频率相关性,空间…

升压斩波电路的simulink建模与仿真

1.课题概述 升压斩波电路的simulink建模与仿真,通过双闭环结构实现电池,点击的控制。2.系统仿真结果3.核心程序与模型 版本:MATLAB2022a 4.系统原理简介升压斩波电路(Boost Chopper Circuit)是一种电力电子转换电路,主要用于将输入直流电压升高到更高的直流电压水平。该电…

代理工具

nc 简介 Netcat是一个简单的Unix工具,用于在TCP或UDP协议上读取和写入数据。由于其简单、灵活的特性,它经常被用于网络调试或在各种网络脚本中。 TCP协议 概述 TCP(传输控制协议)是一种面向连接的协议,用于在网络上可靠地传输数据。它提供了一种可靠的、有序的、基于字节流…

Powershell 重新排列去重 Windows环境变量

最近乱搞环境变量,然后有些重复了,遂写个脚本去重下排序下。 环境变量有长度限制,如果超出了,比如SqlServer相关的,将共同路径单独搞个变量声明下,比如将其路径手动替换成如下,可大幅压缩变量长度但是,Powershell脚本在获取环境变量时又会将这些恢复成原路径,建议点击…

Powershell 重新排列 Windows环境变量

最近乱搞环境变量,然后有些重复了,遂写个脚本去重下排序下。 环境变量有长度限制,如果超出了,比如SqlServer相关的,将共同路径单独搞个变量声明下,比如将其路径手动替换成如下,可大幅压缩变量长度但是,Powershell脚本在获取环境变量时又会将这些恢复成原路径,建议点击…

英文网站文档-翻译

英文网站文档-翻译 背景: 遇到一些英文文档,需要本地制作成文档查看,且需要改成中文 ‍ 步骤找到应用软件 批量下载文档 执行翻译‍ 涉及到的工具: 1. 整站下载软件:sitSucker(mac 版本) ​​ ‍ 附:一批整站下载工具(下载神器) ‍ ‍ 2. 批量翻译脚本工具 ​​ ‍ 按…

音频转换芯片DP7344兼容CS4344双通道24位DA转换器

产品简介DP7344 是一款完整的 2 通道输出数模转换芯片,内含插值滤波器、Multi-Bit 数模转换器、输出模拟滤波器,并支持大部分的音频数据格式。DP7344 基于一个带线性模拟低通滤波器的四阶 Multi-BitΔ∑调制器,自动检测信号频率和主时钟频率,在 2KHz 和 200KHz 之间自动调节…

45岁大龄程序员自述:我居然还苟在程序人生里,但是已经难以为继

世界那么大,我想去看看...记不清好久没来写随笔发水文吐槽了,这篇文章本来是想在园子里首发的,结果鬼使神差发在了头条里面。这起因就是好 (45岁大龄程序员自述:我居然还苟在程序人生里,但是已经难以为继)原文不会打歌么学打歌阿哥怎摆你怎摆,大江大海江大海 ... 瞧,这个…

【YashanDB知识库】数据库获取时间和服务器时间不一致

本文转自YashanDB官网,具体内容可见[https://www.yashandb.com/newsinfo/7352662.html?templateId=1718516] 【问题分类】功能使用 【关键字】服务器时间、数据库时间 【问题描述】数据库获取的时间和服务器时间不一致。【问题原因分析】YashanDB并没有时区的概念,数据库的时…

Ubuntu 22.04 AX211 驱动 解决

官网的驱动居然只支持Linux6.10以上,但实际上并不这样? 可以去网站 https://launchpad.net/ubuntu/+source/backport-iwlwifi-dkms可以看到有一个20.04.5,点开下载update版本就好了 下载后,在对应文件夹里打开终端,输入sudo dpkg -i backport,按tab补全 它会先删除当前的网…

PbootCMS留言自定义表单怎么调用

在 PBootCMS 中,你可以通过自定义表单和标签来实现留言功能。以下是详细的步骤和示例代码,帮助你在全站任意地方使用留言表单和留言记录列表。 1. 留言提交表单 示例代码<form action="{pboot:msgaction}" method="post">联系人:<input type=&…

【YashanDB知识库】archivelog磁盘满导致数据库abnormal

本文转自YashanDB官网,具体内容可见[https://www.yashandb.com/newsinfo/7352661.html?templateId=1718516] 【问题分类】功能使用 【关键字】磁盘空间满,archivelog日志,archivelog自动清理 【问题描述】数据库状态变更为abnormal,检查V$DIAG_INCIDENT视图,发现提示信息…