如何创建 Qt 插件?
简单三部曲
- 定义接口类或接口基类并使用
Q_DECLARE_INTERFACE
宏进行声明 - 所有的插件都需要继承该基类并继承 QObject(不带界面插件) or QWidget(带界面插件)
- 在插件类中添加
Q_PLUGIN_METADATA
导出元数据,使用Q_INTERFACES
指定继承基类(该基类需要使用Q_DECLARE_INTERFACE
声明过)
如何生成?
示例
*.pro 文件内容如下
# 插件依赖模块
QT += core gui widgets
# 生成目标文件名称
TARGET = FlowWidget
TEMPLATE = lib
CONFIG += plugin
# 插件输出目录
DESTDIR = $$[QT_INSTALL_PLUGINS]/generic
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES +=
flowWidget.cpp
HEADERS +=
flowWidget.h
DISTFILES += FlowWidget.json
include($$PWD/interface/interface.pri)
interface.pri
内容如下:
SOURCES +=
HEADERS +=
$$PWD/flowInterface.h
INCLUDEPATH += $$PWD
纯接口类定义如下:
#include <QtPlugin>
class QImage;
class QString;
class QWidget;
class FlowInterface
{
public:
FlowInterface() {}
virtual ~FlowInterface() {}
virtual void process() = 0;
/*!
属性页
*/
virtual QWidget *propertyPage() = 0;
};
#define FlowInterface_iid "com.xiongwei.cheung.FlowInterface"
Q_DECLARE_INTERFACE(FlowInterface, FlowInterface_iid)
注意:在插件类中我们需要实现接口中定义的纯虚函数
插件定义分为带界面和不带界面两种,采用多重继承的方式分别继承 QWidget 或 QObject 即可.
- 带界面插件定义如下:
class FlowWidget : public QWidget , FlowInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.xiongwei.cheung.FlowWidget" FILE "FlowWidget.json")
Q_INTERFACES(FlowInterface)
public:
explicit FlowWidget(QWidget *parent = nullptr);
void process();
QWidget *propertyPage();
signals:
public slots:
private:
};
FlowWidget::FlowWidget(QWidget *parent) : QWidget(parent)
{
}
void FlowWidget::process()
{
// to do something
}
QWidget *FlowWidget::propertyPage()
{
return this;
}
FlowWidget.json
文件是可选的,可通过该文件实现密钥插件
{
"Keys" : [ "FlowWidget" ]
}
- 不带界面插件定义如下:
class FlowObject : public QObject , FlowInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.xiongwei.cheung.FlowObject")
Q_INTERFACES(FlowInterface)
public:
explicit FlowObject(QObject *parent = nullptr);
void process();
QWidget *propertyPage();
signals:
public slots:
private:
};
FlowObject::FlowObject(QObject *parent) : QObject(parent)
{
}
void FlowObject::process()
{
// to do something
}
QWidget *FlowObject::propertyPage()
{
return nullptr;
}
如何使用?
在 main.cpp
文件中添加插件加载路径
QCoreApplication::applicationDirPath().append("generic");
在工程文件中包含插件接口基类文件 flowInterface.h
#include <QPluginLoader>
#include "flowInterface.h"
void load()
{
// 添加一个枚举目录所有动态库文件即可加载所有插件
QPluginLoader pluginLoader("FlowWidget.dll");
// 打印插件元数据,即 json 文件内容中的键值数据
qDebug() << pluginLoader.metaData();
// 加载该插件
QObject *plugin = pluginLoader.instance();
if (plugin) {
// 转换成接口基类指针
FlowInterface *p = qobject_cast<FlowInterface *>(plugin);
if (p){
// 显示界面
p->propertyPage()->show();
}
}
}
注意一个插件类中只能存在一个 Q_PLUGIN_METADATA
宏,使用该宏会导出 qt_plugin_instance
和 qt_plugin_query_metadata
俩个函数。
显然如果使用 2 次 Q_PLUGIN_METADATA
宏会导致函数重定义.
实际上如果向导出多个插件的可以使用 QGenericPlugin
的手法根据 keys
and `` 创建不同的对象.