利用插件扩展Qt应用程序
来源:互联网 发布:国外java高并发书籍 编辑:程序博客网 时间:2024/05/18 18:19
简述
不仅 Qt 本身可以通过插件进行扩展,而且 Qt 应用程序也可以通过插件来扩展,这需要应用程序使用 QPluginLoader
检测和加载插件。在这种情况下,插件可能提供任意功能,不限于数据库驱动程序、图像格式、文本编解码器、样式以及扩展 Qt 功能的其他类型的插件。
- 简述
- 扩展 Qt 应用程序
- 一个简单的插件
- 编写插件
- 加载插件
- 源码地址
版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820
扩展 Qt 应用程序
编写扩展 Qt 应用程序的插件,涉及以下步骤:
- 声明一个继承自
QObject
和插件想要提供的接口的插件类 - 使用
Q_INTERFACES()
宏来告诉 Qt 元对象系统有关接口的情况 - 使用
Q_PLUGIN_METADATA()
宏导出插件 - 使用合适的
.pro
文件构建插件
通过插件使应用程序可扩展,涉及以下步骤:
- 定义一组用于与插件通信的接口(只有纯虚函数的类)
- 使用
Q_DECLARE_INTERFACE()
宏来告诉 Qt 元对象系统有关接口的情况 - 在应用程序中使用
QPluginLoader
加载插件 - 使用
qobject_cast()
来测试插件是否实现了指定的接口
一个简单的插件
为我们的职业感到自豪,程序员可以创造世界。。。以此为例吧!
编写插件
工程文件 -
.pro
和前面一样,由于我们正在构建的是一个共享库,所以在 .pro
中,需要将 TEMPLATE
设置为 lib,同时还必须将 CONFIG
设置为 plugin。
plugin.pro
内容如下:
QT += coreQT -= guiTEMPLATE = libCONFIG += pluginTARGET = personPluginHEADERS += \ person.h \ programmer.hSOURCES += programmer.cppOTHER_FILES += programmer.jsonwin32 { CONFIG(debug, release|debug):DESTDIR = ../debug/plugins/ CONFIG(release, release|debug):DESTDIR = ../release/plugins/} else { DESTDIR = ../plugins/}
这里,将插件生成在 plugins
目录中,当然,目录名可以随便起。
接口类 -
IPerson
声明了一个关于人的接口类 - IPerson
,定义了插件将提供的功能。
注意: 接口是一个仅由纯虚函数组成的类,如果在类中存在非虚函数,那么在 moc 文件中会出现误导的编译错误。
person.h
内容如下:
#ifndef PERSON_H#define PERSON_H#include <QtPlugin>#include <QString>class IPerson{public: virtual ~IPerson() {} virtual QString name() = 0; // 人有名字 virtual void eat() = 0; // 人需要吃东西 virtual void sleep() = 0; // 人需要睡觉 virtual void doSomething() = 0; // 人还需要干其他事};#define IPerson_iid "org.qt-project.Qt.Examples.IPerson"Q_DECLARE_INTERFACE(IPerson, IPerson_iid)#endif // PERSON_H
使用 Q_DECLARE_INTERFACE
宏,是为了让 Qt 元对象系统知道该接口,这样以来,在运行时便可以识别实现接口的插件。其中,第二个参数(IPerson_iid
)是一个标识接口的字符串,必须唯一。
插件类 - Programmer
现在,是时候该程序员出场了。定义一个 Programmer
类,继承自 QObject
和 IPerson
,使这个类成为一个插件。
programmer.h
内容如下:
#ifndef PROGRAMMER_H#define PROGRAMMER_H#include "person.h"#include <QObject>class Programmer : public QObject, IPerson{ Q_OBJECT Q_PLUGIN_METADATA(IID IPerson_iid FILE "programmer.json") Q_INTERFACES(IPerson)public: virtual QString name() Q_DECL_OVERRIDE; virtual void eat() Q_DECL_OVERRIDE; virtual void sleep() Q_DECL_OVERRIDE; virtual void doSomething() Q_DECL_OVERRIDE;};#endif // PROGRAMMER_H
Q_INTERFACES
宏用于告诉 Qt 该类实现的接口。Q_PLUGIN_METADATA
宏包含插件的 IID
,并指向一个包含插件元数据的 Json 文件。该 Json 文件会被编译到插件中,无需安装。
程序员日常:吃饭、睡觉、撸代码。。。(⊙o⊙)…
programmer.cpp
内容如下:
#include "programmer.h"#include <QtDebug>QString Programmer::name(){ return "Pony";}void Programmer::eat(){ qDebug() << "Pizza";}void Programmer::sleep(){ qDebug() << "6 hours";}void Programmer::doSomething(){ qDebug() << "Coding...";}
插件的元数据 - Json 文件
插件已经基本完成,但貌似还缺些什么?没错,元数据!插件总需要提供一些相关的信息吧!
这时上面提到的 Json 文件就相当有用了!可以包含一些元数据,例如:作者、日期、插件名、版本号、依赖关系等。。。
programmer.json
内容如下:
{ "author" : "Waleon", "date" : "2017/09/01", "name" : "personPlugin", "version" : "1.0.0", "dependencies" : []}
由于现在只有一个插件,并没有对于其他插件的依赖,所以暂时没有列出依赖关系(要实现一个插件系统,依赖关系必不可少)。
注意: 如果不想为插件提供信息,当然不会有任何问题,只需保证 Json 文件为空就行。
加载插件
一切准备就绪,来实现一个简单的控制台应用程序,以动态加载插件。
工程文件 -
.pro
由于这里需要的是一个简单的控制台应用程序,所以,除了将 TARGET
设置为 app 之外,还需要将 CONFIG
设置为 console。
app.pro
内容如下:
QT += coreQT -= guiCONFIG += c++11TARGET = appCONFIG += consoleTEMPLATE = appINCLUDEPATH += $$PWD/..SOURCES += main.cppwin32 { debug:DESTDIR = ../debug/ release:DESTDIR = ../release/} else { DESTDIR = ../}
为了能在程序中使用插件相关的接口,需要使用 INCLUDEPATH
将插件的相关路径包含进来。
main() 函数
注意: 对于使用插件的应用程序,Qt 插件只是一个 QObject
,该 QObject
使用多重继承来实现插件接口。
main.cpp
内容如下:
#include <QCoreApplication>#include <QPluginLoader>#include <QDir>#include <QtDebug>#include <QJsonObject>#include <QJsonArray>#include <plugin/person.h>void loadPlugin(){ // 进入插件目录 QDir pluginsDir(qApp->applicationDirPath()); pluginsDir.cd("plugins"); // 查找目录中的所有插件 foreach (QString fileName, pluginsDir.entryList(QDir::Files)) { QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); // 返回插件的根组件对象 QObject *pPlugin = loader.instance(); if (pPlugin != Q_NULLPTR) { // 获取元数据(名称、版本、依赖) QJsonObject json = loader.metaData().value("MetaData").toObject(); qDebug() << "********** MetaData **********"; qDebug() << json.value("author").toVariant(); qDebug() << json.value("date").toVariant(); qDebug() << json.value("name").toVariant(); qDebug() << json.value("version").toVariant(); qDebug() << json.value("dependencies").toArray().toVariantList(); // 访问感兴趣的接口 IPerson *pPerson = qobject_cast<IPerson *>(pPlugin); if (pPerson != Q_NULLPTR) { qDebug() << "********** IPerson **********"; qDebug() << pPerson->name(); pPerson->eat(); pPerson->sleep(); pPerson->doSomething(); } else { qWarning() << "qobject_cast falied"; } } }}int main(int argc, char *argv[]){ QCoreApplication a(argc, argv); loadPlugin(); return a.exec();}
初始化 pluginsDir
成员变量,以引用 plugins
子目录。然后,使用 QDir::entryList()
获取该目录中所有文件列表,并通过 foreach
迭代结果,尝试使用 QPluginLoader
加载插件。
插件提供的 QObject
可以通过 QPluginLoader::instance()
访问。如果动态库不是 Qt 插件,或者是由不兼容版本的 Qt 库进行编译,QPluginLoader::instance()
将返回一个空指针。
对于每个插件,可以根据 QPluginLoader::metaData()
来获取其元数据(定义在 Json 文件中)。要检查插件实现的接口,需要使用 qobject_cast()
,从而进一步访问接口中的定义。
源码地址
GitHub 源码地址:PersonPlugin
- 利用插件扩展Qt应用程序
- 利用插件扩展Qt本身
- 【转】Qt 扩展插件
- QT创建应用程序插件
- Qt 扩展-扩展部件和插件
- qt vs2010创建应用程序插件
- 从Qt扩展上建立一个应用程序
- 如何利用jQuery扩展自己的插件
- 使用Qt编写模块化插件式应用程序
- 使用Qt编写模块化插件式应用程序
- 使用Qt编写模块化插件式应用程序
- 使用Qt编写模块化插件式应用程序
- 使用Qt编写模块化插件式应用程序
- 使用Qt编写模块化插件式应用程序
- 使用Qt编写模块化插件式应用程序
- 使用Qt编写模块化插件式应用程序
- 使用Qt编写模块化插件式应用程序
- 使用Qt编写模块化插件式应用程序
- 简历项目总结
- Qt显示PDF之四pdfium封装
- Qt 信号-槽的同步与异步处理
- Loss Function的修改启发
- zabbix自动发现network
- 利用插件扩展Qt应用程序
- CODE[VS]1010 过河卒
- jetty servlet容器(转自博客园)
- idea maven项目找不到 mapper.xml sql映射文件问题
- 注释必备
- 如何在Windows下安装numpy?
- tomcat启动报错
- .Net 中关于序列化和反序列化Json的方法
- 分析Hive表和分区的统计信息(Statistics)