Qt插件系统
说明
近期入职新公司,新公司的项目用到了Qt的插件系统,花时间了解了一下,还以为Qt的插件系统有多么高级呢,原来归根到底还是 dll 的动态调用时获取其中的类那一招啊,原理和之前的文章《DLL的动态加载》 的里使用 使用dll中的类 描述的方法如出一辙,只是Qt利用了其库的优势。
动态加载dll获取类
在 《DLL的动态加载》 文章说已经说明,dll只可以导出函数,不可以导出指针,但是为了能得到dll中的类,可以导出一个接口,使用接口获取对象指针。但是在dll的调用一方,却无法识别获取到的类指针,所以利用C++的多态和继承的特性来完成。使用抽象类,声明好抽象接口,将需要导出的类继承自该抽象类,并实现其声明的接口。dll的导出方和调用方公用一个抽象类声明文件,在dll导出函数内部,利用多态,将抽象的类指针new成子类对象,并返回出来,则调用方就可以识别得到的类指针了。具体方法说明请参考文章《DLL的动态加载》 。
Qt的插件系统
Qt的插件系统原理(这里只讨论High-Level API)与此相同,只是Qt利用了其内部非特性,使用QPluginLoader替代了导出类指针的接口,并使用宏定义进行导入和导出,避免了在导出导出上因为为了兼容C语言而导致的一些问题,并简化了一些操作。
使用方法
既然原理相同,则需要的文件也相同,需要导出的dll文件和抽象类的声明文件。不同点是,不需要在使用C风格的函数导出类指针了,Qt里面使用宏定义替代。
步骤:
- 定义抽象类,并声明需要用到的接口;
- 使用 Q_DECLARE_INTERFACE() 宏定义将这个抽象类的信息告诉Qt的元对象系统;
- 建立dll项目,继承自 QObject 和这个抽象类,并实现其接口,我们称这个项目为插件;
- 在插件的头文件中使用 Q_PLUGIN_METADATA() 宏定义导出这个插件;
- 在插件项目的.pro文件中配置导出设置,编译生成dll;
- 在dll调用程序中加载dll;
示例代码:
插件项目plugin:
HEADERS += \
plugin.h
SOURCES += \
plugin.cpp
QT += widgets
DISTFILES += \
plugin.json
CONFIG += plugin #表示用于lib模板:库是一个插件
TEMPLATE = lib #表示生成库文件
//plugin.h
class Plugin : public QObject, public PluginInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID pluginInterface_iid FILE "plugin.json")
Q_INTERFACES(PluginInterface)
public:
explicit Plugin(QObject *parent = 0);
~Plugin();
void SayHello(QWidget* parent) Q_DECL_OVERRIDE;
};
说明:
- 必须多继承自 QObject 和抽象类;
- Q_PLUGIN_METADATA 用于声明元数据,IID 是必须且唯一的,FILE 是可选的,后面跟着一个json文件,用于描述插件的相关数据信息;
- Q_INTERFACES 的作用是将所实现的插件接口通知给元类型系统,参数是抽象类类名;
- Q_DECL_OVERRIDE 用于表示这是一个虚函数,编译器会检查这个方法是不是父类中所有的,若没有则报错(类似java中的@Override注解);
//plugin.cpp
Plugin::Plugin(QObject *parent) : QObject(parent)
{
qDebug()<<"constructor";
}
Plugin::~Plugin()
{
qDebug()<<"destructor";
}
void Plugin::SayHello(QWidget *parent)
{
QMessageBox::information(parent, "plugin", "hello, this is dynamically loaded.");
}
{
"Keys" : [ "plugin" ]
}
调用项目test:
插件生成的dll文件copy到执行目录下,共调用方加载
//interface.h
class PluginInterface
{
public:
virtual ~PluginInterface(){}
virtual void SayHello(QWidget* parent) = 0;
};
#define pluginInterface_iid "io.qt.dynamicplugin"
Q_DECLARE_INTERFACE(PluginInterface, pluginInterface_iid)
说明:
- Q_DECLARE_INTERFACE 宏告诉Qt,这是一个插件接口,第一个参数是接口类名,第二个参数是插件标识符,大小写敏感,且唯一;
//调用部分
PluginInterface* interface = NULL;
QPluginLoader plugin_loader("plugin.dll");
QObject* plugin = plugin_loader.instance();
if(plugin)
{
interface = qobject_cast<PluginInterface*>(plugin);
if(interface)
{
interface->SayHello(this);
}
//delete plugin;
plugin_loader.unload();
}
注:Qt文档中说明,QPluginLoader 释放之后,其获取到的插件不会释放,所以,需要手动 delete 插件,或者使用 unload() 方法释放。
Qt插件系统的更多相关文章
- 【大话QT之十六】使用ctkPluginFramework插件系统构建项目实战
"使用ctkPluginFramework插件系统构建项目实战",这篇文章是写博客以来最纠结的一篇文章. 倒不是由于技术都多么困难,而是想去描写叙述一个项目架构採用ctkPlugi ...
- 【夸QT在十五】ctkPluginFrameWork插件系统Windows编译器
采用ctkPluginFramework作为一个插件系统开发框架确实有很多优点. 有些车站最近收到的一封信,每个人都想用ctkPluginFramework但我不知道如何建立,本教程对谈ctkPlug ...
- ctkPlugin插件系统实现项目插件式开发
插件式开发体会: 自开始写[大话QT]系列就开始接触渲染客户端的开发,说是开发不如更多的说是维护以及重构,在接手这块的东西之前自己还有点犹豫,因为之前我一直认为客户端嘛,没什么技术含量,总是想做比较有 ...
- QT皮肤系统的动态切换
应用需求: 提供皮肤切换选项,在不重启应用程序的情况下实现皮肤的动态切换. 理论基础: 1) 图片资源是如何被利用的 这里先简要说明一下实现原理,皮肤的动态切换其关键在于图片资源的加载方式.QT中每个 ...
- 【Win10+eclipse+MinGW+QT安装教程】已有eclipse环境下配置QT插件出错详解
(纪念一下装了一整天濒临绝望的自己[/doge]) (以下所有下载项一律使用32位) step1:下载安装eclipse.适配的jdk.MinGW和QT 1.下载32位eclipse for c++以 ...
- [Qt Creator 快速入门] 第9章 国际化、帮助系统和Qt插件
一.国际化 国际化的英文表述为Internationalization,通常简写为I18N(首尾字母加中间的字符数),一个应用程序的国际化就是使该应用程序可以让其他国家的用户使用的过程. Qt支持现在 ...
- 设置qt插件路径
1.在Qt中使用 WebKit 浏览器核心 使用 QtWebKit 需要在工程文件(*.pro)中加入: QT +=webkitQT += network 2.QtWebKit的flash支持 QtW ...
- Win7下安装VS2017、安装Qt5.10.1以及在VS2017添加qt插件
一.安装VS2017 1.下载VS2017 进入vs下载官网https://www.visualstudio.com/zh-hans/downloads/,选择所需要的vs版本,进行在线安装. 2.安 ...
- CloudNotes之桌面客户端篇:插件系统的实现
[CloudNotes版本更新历史与各版本下载地址请点击此处] [CloudNotes中文系列文章汇总列表请点击此处] [查看CloudNotes源代码请点击此处] 有时候,同一个名词,针对不同的人群 ...
随机推荐
- 端口扫描工具nmap的常用参数讲解
转载请注明出处:https://www.cnblogs.com/wangyanzhong123/p/12576406.html nmap下载与安装 这个没什么好说的.很简单官网上下载就ok了,需要注意 ...
- 【LeetCode】23.合并K个排序链表
题目描述 23.合并K个排序链表 合并k个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入: [ 1->4->5, 1->3->4, 2->6 ] ...
- 使用d3.js的时候,如何用zoom translate scale限制拖拽范围
红色代表需要改写的代码 1.添加定义图像大小和容器的大小及坐标 d3.behavior.zoom = function () { var moveCanvas={ width: , height: , ...
- Hadoop权威指南(中文版-带目录索引)pdf电子书
Hadoop权威指南(中文版-带目录索引)pdf电子书下载地址:百度网盘点击下载:链接:https://pan.baidu.com/s/1E-8eLaaqTCkKESNPDqq0jw 提取码:g6 ...
- [Abp vNext 入坑分享] - 1.创建初始的项目
一.简要说明 本篇文章主要是跟着官方的文档把项目安装好先,同时了解一下大概的项目结构. 二.具体步骤 2.1全局安装ABP CLI,直接在cmd中安装即可.如果你之前安装过,这里可以略过: dotne ...
- 《Spring In Action》阅读笔记之装配bean
Spring主要装配机制 1.在XML中进行显式配置 2.在Java中进行显式配置 3.隐式的的bean发现机制和自动装配 自动化装配bean Spring从两个角度来实现自动化装配 1.组件扫描:S ...
- Java 创建 Excel 数据透视表
Excel 数据透视表具有强大的数据处理功能,能够使表格中的数据更加直观化.使用Excel 数据透视表,能方便用户快速的排序. 筛选各种数据,同时也能满足用户对不同数据汇总的需求.本文将介绍如何在Ja ...
- 5. 配置项:rule_files
prometheus配置文件内容: global: # 默认情况下抓取目标的频率. [ scrape_interval: <duration> | default = 1m ] # 抓取超 ...
- c++四舍五入函数round()
其实c++自身是没有四舍五入函数round()的,若果你要用到的话,可以自己写一个round(),不过要用到floor()和ceil这两个函数如下: #include<iostream> ...
- thinkphp if便签的使用
<foreach name="list" item='v'> <tr> <td><img class="user" s ...