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的插件方法教程结束。