参考文档:https://www.jianshu.com/p/625057deaeac

QT中的插件分类:

  1. 纯C++/Qt插件;
  2. 开源的纯QML插件(qmldir);
  3. 隐藏源码的QML插件;
  4. 包含C++的QML插件;

纯C++/Qt插件

开源的纯QML插件(qmldir)

实际是将源码目录直接打包发布。分为带url和不带url前缀的QML插件,import:

1
2
import QtQuick 2.12 // 不带url
import QtQuick.Control 2.12 // 带url

如果插件qml文件存在多级目录,使用.号将目录导入。

以不带url前缀的为例。

创建QML插件

创建文件夹DemoPlugins/,再创建插件qml文件:DemoPlugins/CRect.qml

1
2
3
4
5
6
7
8
import QtQuick 2.12
import QtQuick.Controls 2.12

Rectangle {
width: 100
height: 100
color"red"
}

在qml同级目录创建qmldir文件(DemoPlugins/qmldir),添加如下内容:

1
2
module DemoPlugins
CRectangle 1.0 CRect.qml

使用QML插件

将上面的文件夹DemoPlugin拷贝到使用该插件的Qt工程中/d/projects/TestPlugin,main函数添加:

1
engine.addImportPath("/d/projects/TestPlugin");

在main.qml的使用实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import QtQuick 2.14
import QtQuick.Controls 2.14
import DemoPlugin 1.0

ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("Stack")

CRectangle {
id: cRec
}
}

实际就是将源码目录直接打包发布的过程。

IDE中CRectangle是没有高亮的,想要让QT Creator ide能找到插件,进行高亮,自动补全,在pro文件中添加:

1
QML_IMPORT_PATH += /d/projects/TestPlugin

如果DemoPlugin文件夹相对addImportPath(“/d/projects/TestPlugin”)的目录存在多级目录,即带url的插件,则需要修改qmldir:

1
2
module dir1.DemoPlugins
CRectangle 1.0 CRect.qml

main.qml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import QtQuick 2.14
import QtQuick.Controls 2.14
import dir1.DemoPlugin 1.0

ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("Stack")

CRectangle {
id: cRec
}
}

隐藏源码的QML插件

实际开发过程中,需要将源码封装打包,不对外提供源码。此时需要借助QQmlExtensionPlugin这个类,以及QT的资源管理系统。

创建插件工程

新建->Library->Qt Quick2 Extension Plugin,创建插件工程:

  • 工程名字:rectplugin
  • object class name: 随意,后续可以修改;
  • url: 上节说到的import路径相关,使用DemoPlugin1(也可以使用多级目录com.mycompany.mymodule);

添加qml文件

创建qml.qrc资源文件,添加CRect1.qml文件:

1
2
3
4
5
6
7
8
import QtQuick 2.12
import QtQuick.Controls 2.12

Rectangle {
width: 100
height: 100
color"green"
}

修改rectplugin_plugin.cpp的registerTypes():

1
2
3
4
5
6
7
void QmlpluginPlugin::registerTypes(const char *uri) {

qmlRegisterType(QUrl("qrc:/CRect1.qml"), uri, 1, 0,
"CRectangle1");
// qmlRegisterType(QUrl("qrc:/CRect2.qml"), uri, 1, 0,
// "CRectangle2");
}

如果有多个需要暴露的qml控件,可以添加到这里。

构建构成,在构建目录下拷贝qmldir(和工程目录下的qmldir一致,如果需要修改生效,修改工程下的qmldir文件)和rectplugin.dll(linux为.so,以及debug输出为***d.dll)文件,至DemoPlugin1(和qmldir文件中的module保持一致即可)文件夹中。

使用示例

修改main.qml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import QtQuick 2.14
import QtQuick.Controls 2.14
import DemoPlugin1 1.0

ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("Stack")

CRectangle1 {
id: cRec
}
}

生成.qmltypes文件实现高亮显示

qmlplugindump格式:
格式:qmlplugindump -nonrelocat Arg1 Arg2 Arg3 Arg4

Arg1 :module[插件]名称

Arg2 :module[插件]版本

Arg3 :插件所在的父路径

Arg4 :xxx.qmltypes的生成路径,一般是和qmldir一样的路径

1
qmlplugindump.exe -nonrelocatable DemoPlugin1 1.0 /d/projects/TestPlugin > /d/projects/TestPlugin/DemoPlugin1/plugins.qmltypes

可以看到/d/projects/TestPlugin/DemoPlugin1/plugins.qmltypes文件。

如果qmlplugindump.exe找不到,注意添加QT的环境变量,或者直接使用路径找到该exe。

在/d/projects/TestPlugin/DemoPlugin1/qmldir中添加:

1
2
3
module DemoPlugin1
plugin rectplugin
typeinfo plugins.qmltypes

包含C++的qml插件

可以参考Qt Creator自带example

创建插件工程,本文这里共用上一小节的工程。

创建需要的c++类CPlugin。

添加QPlugin.qml:

1
2
3
4
5
6
import QtQuick 2.12
import DemoPlugin1 1.0

QCPlugin {

}

如果插件的使用不需要经过QPlugin.qml,也可以不添加。

修改rectplugin_plugin.cpp的registerTypes():

1
2
3
4
5
6
7
8
9
10
void QmlpluginPlugin::registerTypes(const char *uri) {
Q_ASSERT(uri == QLatin1String("DemoPlugin1"));
qmlRegisterType<CPlugin>(uri, 1, 0, "QCPlugin");
qmlRegisterType(QUrl("qrc:/QPlugin.qml"), uri, 1, 0,
"QPlugin");
qmlRegisterType(QUrl("qrc:/CRect1.qml"), uri, 1, 0,
"CRectangle1");
// qmlRegisterType(QUrl("qrc:/CRect2.qml"), uri, 1, 0,
// "CRectangle2");
}

注意:注册的名字不必和原文件或这原类名保持一致。

构建,拷贝dll和qmldir文件。同之前小节

使用示例

使用方式和之前小节相似,main.qml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import QtQuick 2.14
import QtQuick.Controls 2.14
import DemoPlugin1 1.0

ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("Stack")

// method1
QPlugin {
}

// method 2
QCPlugin {

}
}

两种控件都是有效的。