(本文编码-编译环境为Qt5.12.6+QtCreator4.10.2+MSVC2019)
制作插件or动态库是很常见的需求,QtQuick也提供了这一功能,插件的源码既可以是QML的,也可以是C++的。
(可以参照官方示例:qml plugin)
在QtCreator中点新建项目,在对话框中选择 Qt Quick 2 Extension Plugin,就可以创建一个简单的插件项目。
除了工程名和 uri 名,一路默认就行了,先把流程跑通(uri由com.mycompany.qmlcomponents改为和dll一样的名字)。可以看到,它默认生成了一个 lib 项目(TEMPLATE = lib),里面还包含一个 qmldir 文件,这个文件比较重要,dll 路径里没有它的话编辑器没法找到这个模块,也就没法自动提示了。此外,工程默认生成了一个 QQuickItem 的派生类,并在 -plugin.cpp 文件里注册为了 QML 类型, QQuickItem 对应QML 中的 Item 类型,对于非可视类型,我们继承 QObject 就行了。
既然工程默认生成了 MyItem ,那我直接用这个类来自定义。作为演示,我定义了一个属性和一个函数。
//myitem.h
#ifndef MYITEM_H
#define MYITEM_H
#include
class MyItem : public QQuickItem
{
Q_OBJECT
Q_DISABLE_COPY(MyItem)
//自定义属性
Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
public:
explicit MyItem(QQuickItem *parent = nullptr);
~MyItem() override;
QString getName() const;
void setName(const QString &name);
//自定义方法
Q_INVOKABLE int getStringLength(const QString &str);
signals:
void nameChanged();
private:
QString _name;
};
#endif // MYITEM_H
//myitem.cpp
#include "myitem.h"
MyItem::MyItem(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);
}
MyItem::~MyItem()
{
}
QString MyItem::getName() const
{
return _name;
}
void MyItem::setName(const QString &name)
{
if(_name!=name){
_name=name;
emit nameChanged();
}
}
int MyItem::getStringLength(const QString &str)
{
return str.length();
}
构建之后会生成 dll,这里先手动创建一个 dll 模块同名的文件夹,然后把 dll 以及 qmldir 文件放进去,并把文件夹放到安装目录的 qml 文件夹下。(相当于install到了安装目录的qml文件夹下)
(2020-2-9补充)除了把文件夹放到环境qml目录里,也可以使用QQmlApplicationEngine的addImportPath指定文件夹所在的目录(qml文件夹本身也在importPath列表中),如:
其中,我们的模块文件夹在路径的下一级。
新建一个 QtQuick 项目,测试刚才生成的插件:
import QtQuick 2.12
import QtQuick.Window 2.12
import TestQml_20200124_Plugin 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MyItem{
name: "test"
Component.onCompleted: {
console.log(name)
let length=getStringLength("asdaa")
console.log(length)
}
}
}
如果操作正确,可以正常运行:
第一点:我没发现Qt有提供编译时安装的CONFIG,一般是使用copy命令或者make参数加上install,在上面的例子中为了简化步骤,我用的手动复制文件的方式(之所以copy到Qt安装目录而不是放到任意目录然后用includepath的方式,因为我自己感觉这样用起来方便一点,不用单独去配置路径);第二点:一开始我没管命名, dll和module uri和文件夹名字都不一样,导致编辑的时候可以识别,但是运行起来就找不到这个模块了,索性我直接把名字统一了;第三点:很多人用qmlplugindump来生成qmltypes描述文件,但是目前还没发现该文件的必要性(难道是因为我放在了安装目录能被编辑器检测到并触发高亮?),以后我用到了再补充。
在 QQmlExtensionPlugin 派生类中,通过重写 registerTypes 方法,可以注册我们自己的组件,使用 qmlRegisterType 等函数可以将 C++ 类型注册给 QML(和我们平时注册C++类型是一样的操作),也可以使用 Q_INIT_RESOURCE 宏包含 .qrc 文件,文件里放有我们的 QML 代码,达到封装 QML 组件的目录。
我做了一个简单的示例,git链接在底部,要注意的是我使用的msvc,所以copy文件到安装目录的配置只考虑了win32。
#include
#include "PaintedTest.h"
void JbosPlugin::registerTypes(const char *uri)
{
Q_INIT_RESOURCE(qmlitem);
// @uri EasyJbos
qmlRegisterType(uri, 1, 0, "PaintedTest");
}
项目链接: https://github.com/gongjianbo/EasyJbos
官方文档:https://doc.qt.io/qt-5/qtqml-modules-cppplugins.html
博客:https://www.cnblogs.com/yanhuiw/p/4719597.html
博客:https://www.cnblogs.com/yanhuiw/p/4722557.html