Qt QML的插件(Qt Quick 2 Extension Plugin)方法

Qt Quick的插件方法

序言

网上有很多的Qt Quick扩展插件方法,比如龚建波或者诺谦的,确实是教了怎么做,可是还是按着做时还是出现了一些问题,有些细节上的理解容易与作者想的不一样,对于新手不太友好,不够简单和全面,起码我看着没有第一时间弄出来,还花了不少时间研究才最终弄出来。

因此我作为更新手的视角也来写一下插件的用法,以供学习的人分别参考。

如果有兴趣,我后面也可以出C++的插件方法,不过感觉资料很多没什么必要。

环境

Qt5.15(MSVC2019)

VS2019

前置注意

示例插件名: TestQmlPlugin

模块名:QmlEditorStyle

插件库名:TestQmlPlugin

概念------Qt Quick插件的相关知识

Qt的插件,有一个很大的特点,就是不需要lib文件,只需要dll文件,就可以进行动态装载。

如果是C++,会需要QPluginLoader进行加载,不过其实也是用的QLibrary。

QML不需要自己来加载,因为Engine已经负责了这个加载任务。

不过相对的,Qt Quick也需要一些信息,比如插件的外接接口的信息,我们提供的就是一个名为:qmldir 的文件,无.txt,.pri那些后缀,就叫qmldir

关于qmldir里面该怎么写,Qt的助手就已经有相关说明:

具体有什么可以自行翻找查阅,但是qmldir最起码需要两条信息,也是我演示用的其中两条:

一个交代了QML的import时的模块名,另一个交代了插件库的库名。

举例:

qmldir文件里只有两行信息:

javascript 复制代码
module QmlEditorStyle
plugin TestQmlPlugin

而其分别影响的是:

module QmlEditorStyle

->

javascript 复制代码
import QmlEditorStyle 1.0

.
plugin TestQmlPlugin

->

TestQmlPlugin.dll

TestQmlPlugind.dll

.

插件里的qml文件

有些人,会想将QML文件放进插件里,这样调用的时候就可以拿着dll随便用了。

可惜,实现不了。

插件本质上是一种特殊的动态库,动态库你我都懂,如果需要调用动态库里面的类,就需要提供一些接口.h文件。

然后编码时才可以自由访问提供的接口类。

同理,你要调用QML文件,就必须要有接口,可怎么提供接口呢?QML文件就没有分什么.h文件,.cpp文件,它是解释型语言,就算用插件,你也需要提供源码才可以。

除非你用C++实现QML的项,然后封装进插件里,再放出.h文件即可。(因为QML的项本质上是QtC++的实现而来的。)

将自己封装好的QML文件放在插件库文件夹里,即下文会提到的QmlEditorStyle文件夹里。

再将qmldir文件夹的末尾,加上资源标识符 注册的版本 对应文件

其对应的就是

cpp 复制代码
qmlRegisterType<MySliderItem>("QmlEditorStyle", 1, 0, "Slider");

ResourceIdentifier对应的是Slider,注册的QML类型

InitialVersion对应的是1, 0,C++是1逗号0,qmldir是1点0

File对应的是MySliderItem,实际的QML文件,C++的是实际的C++类

bash 复制代码
module QmlEditorStyle
...
Slider 1.0 MySliderItem.qml

不过一般都会文件和类型名一致。

这样就算是将QML文件放进插件库里了,当调用该文件夹的插件时,也会囊括QML文件了。

模块名的相关知识

Qt Quick的import模块名,值得注意的是,其代表的其实是文件夹名,什么意思呢?

比如说QtQuick.Window 2.15这个import的模块,实际代表的是QtQuick文件夹里的Window.2文件夹

Creator会根据这个,从路径信息里找到对应的文件夹,找到对应的plugins.qmltypes文件和qmldir文件,进而读取进来。

模块名本身注意事项

有的人可能要自己定义一个插件库,比如说:公司名.库名

然后就打算这样命名文件夹:Company.TestQmlPlugin

这样是行不通的,Creator会找不到插件库的,你得改成 Company文件夹里放TestQmlPlugin文件夹

模块名版本注意事项

那么如果说我们导入示例插件TestQmlPlugin呢?

比如说import TestQmlPlugin 1.0

就直接是TestQmlPlugin文件夹里放就行,后面的.1可加可不加,没有会默认按.1处理

如果是import TestQmlPlugin 2.0

就需要命名为:TestQmlPlugin.2文件夹,这个不能缺少后面的.2

.

另外还需要一个文件,plugins.qmltypes,其提供给Creator提示信息,是由我们用qmlplugindump生成的,或者qmake的里面设置一些东西可以自动生成。

基本这些加上库文件就组成了一个插件。

以示例来说明

创建插件

按选择,创建插件的这个工程名,与提供出来的插件名不影响

选择qmake还是cmake进行编译,Qt6只运行用cmake,如果用QML,以后考虑用Qt6的,就选择cmake。

但是呢,这里现在暂时只讲解qmake方法,cmake待后续添加。

接下来选择一些基本信息,如最低Qt版本这些,URI的com.mycompany.qmlcomponents,可以改为我们示例用的模块名QmlEditorStyle,或者你打算设置的模块名。

.

.

如此就生成了初始的插件

进行构建,就可以生成debug版本或者release版本这些的dll了。

不需要在意debug版本,dll名是否会因为有个d后缀而影响的问题,Qt在读取的时候会自动判断的了。

将构建好的dll和qmldir放进由模块名为文件夹名的文件夹里。

qmltypes的生成

在该文件夹的上一级,用cmd输入:

bash 复制代码
qmlplugindump QmlEditorStyle 1.1 . > .\QmlEditorStyle\plugins.qmltypes

其的输入规则是:

qmlplugindump+空格+模块名+空格+版本+空格+模块所在目录+空格+ > +空格+要生成的路径

需要注意的是,模块所在目录是指以模块名为文件夹名的文件夹所在目录,即QmlEditorStyle文件夹。

生成之后会在模块文件夹里即QmlEditorStyle生成一个plugins.qmltypes,是qmlplugindump根据插件里注册的内容,生成的信息。

qmltypes的可能性失效

1、生成了plugins.qmltypes可能是缺少信息的,也可能是我指令有误之类的吧,但是参考别人的也都是相同的。

注意上方的exports这行信息,在每个MyItem的左边,需要加上模块名QmlEditorStyle/MyItem 1.1

这样才能生效

2、如果上方加上了模块名仍然Creator提示无效,则在qmldir里新增一行:

cpp 复制代码
typeinfo plugins.qmltypes

不过一般来说加不加不影响

3、如果上边的都弄了之后,发现在导入的地方存在一个错误提示
Error 1:1 预计符号numeric literal

这是编码问题,我遇到了,发现plugins.qmltypes是utf-16格式的,于是我转成了utf-8格式的就正常了

.

插件的编码注意

1、插件模块版本控制

Qt Quick的模块版本,是由注册到该版本的项决定是否存在的。

什么意思呢?

testqmlplugin_plugin.cpp里,有个代码

cpp 复制代码
void TestQmlPluginPlugin::registerTypes(const char *uri)
{
	qmlRegisterType<MyItem>(uri, 1, 0, "MyItem");
}

uri代表的是会传入你编写的模块名,比如说该示例是QmlEditorStyle,uri也是这个值。

第二个参数是主版本号,第三个参数是次版本号。

就是import QmlEditorStyle 1.0里的1是主版本号,0是次版本号。

这样将MyItem注册在了1.0这个模块里,1.0就存在了一个MyItem的项。

你如果后面都弄好后平白无故去导入1.1模块也是不存在的,会提示不存在这个模块,因为里面不包含任何项。

2、pro里的注意

cpp 复制代码
TEMPLATE = lib
TARGET = TestQmlPlugin		// 插件的dll名称
QT += qml quick
CONFIG += plugin c++11

TARGET = $$qtLibraryTarget($$TARGET)
uri = QmlEditorStyle		// 代表着模块名,一般用不上

此处如果额外增加下列代码

cpp 复制代码
CONFIG += qmltypes #自动生成 plugins.qmltypes
QML_IMPORT_NAME = TestQmlPlugin
QML_IMPORT_MAJOR_VERSION = 1

就会自动在构建之后产生一个plugins.qmltypes代码了,可以免掉后面再自行命令行用qmlplugindump了。

不过要自行更改QML_IMPORT_MAJOR_VERSION版本,其代表的是主版本号。

.

调用插件

接下来就是怎么去使用我们的插件了

首先,在上文生成插件后,有一个QmlEditorStyle的文件夹。

将这个文件夹放到使用的工程文件下,专门放QML插件的一个文件夹下,我这里是qml文件夹,你也可以命名为DLL或者其他什么的,名字不影响。

插件信息输入

有两处需要填写插件信息的:

第一处是pro里,有个QML_IMPORT_PATH,增加qml所在路径。

cpp 复制代码
QML_IMPORT_PATH += C:/Project/Qt/build-testQtQML-Desktop_Qt_5_15_2_MSVC2019_32bit-Release/release/qml

我这里放的是生成的目标路径位置,也可以放工程里,是一样的,不影响。

第二处是在main.cpp里,有个engine,调用engine增加插件路径。

cpp 复制代码
QQmlApplicationEngine engine;
engine.addImportPath(QString("%1/qml").arg(app.applicationDirPath()));		// 可以用绝对路径之类的,指向qml文件夹
const QUrl url(QStringLiteral("qrc:/main.qml"));
...

第三处是调用处的qml里:

javascript 复制代码
import QtQuick 2.15
import QtQuick.Window 2.15
import QmlEditorStyle 1.1			// 调用对应的模块

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")


    MyItem {			// 使用默认提供的C++的Item
        width: 100
        height: 100
        fillColor: "red"
    }
}

上边如果import QmlEditorStyle 1.1或者MyItem有报错,则是没有配置好。

如果能正常运行,则是plugins.qmltypes没有弄好。

以上全部都弄好后,应该是这样的:

正常显示无报错

item能正常显示

至此,Qt Qucik的插件方法教程结束。

相关推荐
Quz13 小时前
QML Hello World 入门示例
qt
xcyxiner4 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner4 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner5 天前
DicomViewer (添加模型类)3
qt
xcyxiner5 天前
DicomViewer (目录调整) 2
qt
xcyxiner5 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能7 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G7 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt
森G7 天前
77、线程池原理和实现------服务器源码解析----云视频服务项目
服务器·c++·qt
森G7 天前
71、打包发布---------打包发布
c++·qt