制作 QML 扩展插件(Qt Quick 2 Extension Plugin)

(本文编码-编译环境为Qt5.12.6+QtCreator4.10.2+MSVC2019)

制作插件or动态库是很常见的需求,QtQuick也提供了这一功能,插件的源码既可以是QML的,也可以是C++的。

1.做一个最简单的插件

(可以参照官方示例:qml plugin)

1.1.创建 Qt Quick 2 Extension 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 就行了。

1.2.修改 MyItem

既然工程默认生成了 MyItem ,那我直接用这个类来自定义。作为演示,我定义了一个属性和一个函数。

//myitem.h
#ifndef MYITEM_H
#define MYITEM_H

#include <QQuickItem>

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列表中),如:

其中,我们的模块文件夹在路径的下一级。

1.3.使用插件

新建一个 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)
        }
    }
}

如果操作正确,可以正常运行:

1.4.总结

第一点:我没发现Qt有提供编译时安装的CONFIG,一般是使用copy命令或者make参数加上install,在上面的例子中为了简化步骤,我用的手动复制文件的方式(之所以copy到Qt安装目录而不是放到任意目录然后用includepath的方式,因为我自己感觉这样用起来方便一点,不用单独去配置路径);第二点:一开始我没管命名, dll和module uri和文件夹名字都不一样,导致编辑的时候可以识别,但是运行起来就找不到这个模块了,索性我直接把名字统一了;第三点:很多人用qmlplugindump来生成qmltypes描述文件,但是目前还没发现该文件的必要性(难道是因为我放在了安装目录能被编辑器检测到并触发高亮?),以后我用到了再补充。

2.将组件封装为插件

在 QQmlExtensionPlugin 派生类中,通过重写 registerTypes 方法,可以注册我们自己的组件,使用 qmlRegisterType 等函数可以将 C++ 类型注册给 QML(和我们平时注册C++类型是一样的操作),也可以使用 Q_INIT_RESOURCE 宏包含 .qrc 文件,文件里放有我们的 QML 代码,达到封装 QML 组件的目录。

我做了一个简单的示例,git链接在底部,要注意的是我使用的msvc,所以copy文件到安装目录的配置只考虑了win32。

#include <qqml.h>

#include "PaintedTest.h"

void JbosPlugin::registerTypes(const char *uri)
{
    Q_INIT_RESOURCE(qmlitem);
    // @uri EasyJbos
    qmlRegisterType<PaintedTest>(uri, 1, 0, "PaintedTest");
}

项目链接: https://github.com/gongjianbo/EasyJbos

3.参考

官方文档: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

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页