QT5应用程序动态插件的使用
1 概要
在软件开发中可以将某些独立的功能模块作为插件(编译为库文件)来使用。这样做的插件就可以单独发布和升级而不需要修改主程序。
原理上是使用了C++的多态和QT元对象系统。插件功能的使用要分为主程序和插件程序两个部分。下面进行详细的介绍。
制作可扩展(可调用插件)的主程序,步骤如下:
- 定义一些列的操作接口(即抽象类,只有纯虚函数),用于插件内部方法的调用。
- 使用Q_DECLARE_INTERFACE()宏将步骤1定义的接口进行声明,注册到QT的元对象系统中。
- 在调用插件的地方使用QPluginLoader加载插件。
- 使用qobject_cast()将加载的插件转为相应的接口(此方法也可用于测试加载的插件是否为所需要的接口)。
插件程序的编写步骤如下:
- 声明自己的插件类,需要继承自QObject和需要实现的接口类(在制作可扩展应用程序的步骤1中定义的接口)。
- 使用Q_INTERFACES()宏向元对象系统声明所用到的接口。
- 使用Q_PLUGIN_METDATA()宏导出插件。
2 实例
实例项目分为两个子项目,主程序和插件程序,完整实例项目代码点击此处下载。
- 主程序
-
- myInterface接口文件
#ifndef MYINTERFACE_H
#define MYINTERFACE_H
#include <QObject>
class MyInterface
{
public:
virtual void show() = 0;
};
Q_DECLARE_INTERFACE(MyInterface,"MyInterface.1")
#endif // MYINTERFACE_H
此接口只包含了纯虚函数show(),并用Q_DECLARE_INTERFACE对接口进行了声明。
-
- 插件的调用方法
/* 定义接口指针用于操作插件 */
MyInterface *m_interface = NULL;
/* 找到插件所存储的路径 */
QDir pluginDir(qApp->applicationDirPath());
pluginDir.cd("pluginDll");
foreach (QString fileName, pluginDir.entryList(QDir::Files)) {
/* 遍历路径下的所有文件,当做插件进行加载 */
QPluginLoader pluginLoader(pluginDir.absoluteFilePath(fileName));
/* 加载插件并获取插件的实例,加载失败返回NULL */
QObject *plugin = pluginLoader.instance();
if (plugin) {
/* 将插件转换为接口,失败返回NULL */
m_interface = qobject_cast<MyInterface *>(plugin);
if (m_interface)
m_interface->show(); //调用方法
}
}
- 插件程序
-
- plugin.h插件类定义
#ifndef PLUGIN_H
#define PLUGIN_H
#include <QObject>
#include "myInterface.h"
class plugin:public QObject,public MyInterface
{
//以下三个宏不能少
Q_OBJECT
Q_INTERFACES(MyInterface)
Q_PLUGIN_METADATA(IID "MyInterface.1" FILE "data.json")
//Q_PLUGIN_METADATA宏一定要用到,如果没有元数据FILE可以不写直接写成下面这样
//Q_PLUGIN_METADATA(IID "MyInterface.1")
public:
void show();
};
#endif
-
- plugin.cpp插件类实现
#include <QMessageBox>
#include "plugin.h"
void plugin::show()
{
QWidget w;
QMessageBox::warning(&w,"warning","test");
}
-
- plugin.pro项目文件
TEMPLATE = lib #插件编译为库文件
TARGET = plugin
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
CONFIG += plugin #config中加入plugin表示动态插件
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
plugin.cpp
HEADERS += \
plugin.h
INCLUDEPATH += ../pluginMain
DESTDIR = ..bin/pluginDll
OBJECTS_DIR = ./obj
MOC_DIR = ./moc
该类继承自QObject和MyInterface接口,并实现了show函数(简单的显示一个告警对话框)。