前言:
首先搞明白qt中插件的概念:
插件:一个可在运行时加载的动态库
Qt中,使用QPluginLoader加载插件
既然插件是一个动态库,那么把它静态编译到可执行文件中也是允许的
对于使用插件的应用程序来说,Qt 插件就是一个 QObject,只不过这个QObject需要实现插件Interface
PluginDialog::staticInstances()可以获得当前应用程序已经加载的所有插件
由此,可以理解PluginDialog管理所有插件
Qt中的插件分为两种:
1)应用程序插件,即为库封装; 2)Qt Creator插件,即服务于IDE的插件。
这里只讨论第一种,即应用程序插件。
分类:
应用程序插件也分为几种:
1)由c++代码实现,QWidget系列的库(动态库或静态库),这类插件的使用即为库的使用,有头文件和库文件即可;
2)由c++代码实现,集成QQuickItem,导出为qml组件,提供qml使用的库(动态库或静态库),这类插件的使用有别于1),不需要头文件,但是需要qmldir文件替代头文件,qmldir文件用来告知使用者,当前库的import路径是什么吗,同时还需要提供一个plugins.qmltypes文件来告知使用者当前dll中有哪些可用的qml类型,但是这个plugins.qmltypes是可选的;
3)由qml代码实现,直接指定qml文件路径作为import地址,这种方法不需要任何工程辅助,这其实相当于qml的组件技术;
4)由qml代码实现,但是纳入到2)中的工程中,工程输出时,需要把qml文件名列入qmldir文件中,这样其module路径则和c++模块一致。
由c++代码实现,集成QQuickItem(对应第2类)
步骤1:创建插件工程
步骤2:指定module的uri和基础c++类名
步骤3:插件工程说明
pluginexample_plugin.h
#ifndef PLUGINEXAMPLE_PLUGIN_H
#define PLUGINEXAMPLE_PLUGIN_H
#include <QQmlExtensionPlugin>
/* OBT -- 所有qml插件都要继承QQmlExtensionPlugin类 */
class PluginExamplePlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
/* OBT -- 重写此虚函数,此函数用来告知qml引擎当前插件的module uri */
void registerTypes(const char *uri) override;
};
#endif // PLUGINEXAMPLE_PLUGIN_H
pluginexample_plugin.cpp
#include "pluginexample_plugin.h"
#include "obtitem.h"
#include <qqml.h>
void PluginExamplePlugin::registerTypes(const char *uri)
{
/* OBT -- 注册qml类型 */
// @uri ObtPlugin
qmlRegisterType<ObtItem>(uri, 1, 0, "ObtItem"); //尖括号里的为c++类名,"ObtItem"为导出的qml类型
}
obtitem.h
#ifndef OBTITEM_H
#define OBTITEM_H
#include <QQuickItem>
#include <QRect>
/* OBT -- 插件内组件的具体实现 */
class ObtItem : public QQuickItem
{
Q_OBJECT
Q_DISABLE_COPY(ObtItem)
public:
explicit ObtItem(QQuickItem *parent = nullptr);
~ObtItem() override;
};
#endif // OBTITEM_H
obtitem.cpp
#include "obtitem.h"
ObtItem::ObtItem(QQuickItem *parent):
QQuickItem(parent)
{
// By default, QQuickItem does not draw anything. If you subclass
// QQuickItem to create a visual item, you will need to uncomment the
// following line and re-implement updatePaintNode()
// setFlag(ItemHasContents, true);
}
ObtItem::~ObtItem()
{
}
qmldir
module ObtPlugin #模块名称 import时使用
plugin PluginExample #插件文件名称 PluginExample.dll
步骤4:工程输出及使用
工程输出内容如下:
将输出拷贝到一个单独的目录下,同时把qmldir文件也放在一起:
Test.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import ObtPlugin 1.0 //模块路径uri
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ObtItem{ //导出的qml类型
x:20
y:20
width: 100
height: 100
}
}
步骤5:测试
结果可以正常弹窗,此文旨在说明插件的制作和使用,因此没有对ObtItem做任何实现,故窗口是空白的。
qmlscene -I ./ Test.qml 中的 -I ./ 是在当前路径下查找插件,代码中有 import ObtPlugin 1.0 导入插件,所以就需要插件放在 Test.qml 同级路径下的 ObtPlugin 文件夹中 。见步骤4中的目录结构截图。
由qml代码实现(对应3/4类)
将qml文件放到 dll 和 qmldir同级路径下,再在qmldir中添加相应语句即可,比如有 MyRect.qml,则qmldir写为
module ObtPlugin #模块名称 import时使用
plugin PluginExample #插件文件名称 PluginExample.dll
MyRect 1.0 MyRect.qml #添加MyRect.qml文件为ObtPlugin模块管理范围内的组件,通过MyRect来进行调用
文件存放结构: