qml与cpp交互的几种方式

9 篇文章 0 订阅
本文介绍了在QML与C++交互中常用的接口,如qmlRegisterType、qmlRegisterModule等,以及在model/view模式中如何通过cpp与qml交互。重点讲解了qmlRegisterAnonymousType、qmlRegisterExtendedType和qmlRegisterInterface的使用方法。
摘要由CSDN通过智能技术生成

基础知识部分

主体框架,qml必须通过源对象来进行交互,即交互的双方都是QObject的子类,能有一个基础的沟通系统,在qml与cpp交互过程中,鉴于cpp多种设计模式,和对于数据的不同使用和需求,设计了多个接口

在此列举:

qmlRegisterAnonymousType
qmlRegisterExtendedType
qmlRegisterExtendedUncreatableType
qmlRegisterlnterface
qmlRegisterModule
qmlRegisterRevision
qmlRegisterSingletonlnstance
qmlRegisterSingletonType
qmlRegisterType
qmlRegisterTypeNotAvailable
qmlRegisterUncreatableMetaObject
amlRegisterUncreatableType

以下这张图分析了如上这些接口在何种情况下使用:

其中我们最常用的是:qmlRegisterType、qmlRegisterModule,

有些不走上面的方式

比如在model/view中,qt5在qml中的TabView没有对应的model,QT6对其支持也很弱,满足不了需求,因此,qml使用view,cpp作为model成了一种很普遍的方式,根据需求,使用

engine.rootContext()->setContextProperty()这种接口来将cpp文件与qml交互效果比较理想,

附上CSDN大佬写的网址:

C++ 与 QML 之间进行数据交互的几种方法_qml和c++交互-CSDN博客

对于cpp跳过js控制qml控件这种,则提供了另外一些方式:直接从引擎拿到根元素,对根元素进行操作,可以是显示的控件,也可以是数据类型的元素,灵活性非常大,但是在信号与槽函数连接中,由于connect()连接方式必须确定是何种类型发出何种信号,这种方式限制了信号的传递。

auto root = engine.rootObjects();
    // findChild 是qml中的objectName名
auto base = root.first()->findChild<QObject *>("label1");

详解每一种类型的具体使用

qmlRegisterAnonymousType

qmlRegisterAnonymousType() 是一个在 Qt Quick 中用于注册匿名 QML 类型的函数。这个函数允许你在运行时动态地注册自定义的 QML 类型,而无需在 C++ 代码中提前声明这些类型。

代码:cpp部分:

 class Bar : public QObject
 {
     Q_OBJECT
     Q_PROPERTY(QString baz READ baz WRITE setBaz NOTIFY bazChanged)

 public:
     Bar() {}

     QString baz() const { return mBaz; }

     void setBaz(const QString &baz)
     {
         if (baz == mBaz)
             return;

         mBaz = baz;
         emit bazChanged();
     }

 signals:
     void bazChanged();

 private:
     QString mBaz;
 };

 class Foo : public QObject
 {
     Q_OBJECT
     Q_PROPERTY(Bar *bar READ bar CONSTANT FINAL)

 public:
     Foo() {}

     Bar *bar() { return &mBar; }

 private:
     Bar mBar;
 };

注册方式,和qmlRegisterType类型注册一致

qmlRegisterAnonymousType<Bar>("App", 1);

qmlRegisterExtendedType

qmlRegisterExtendedType() 是一个用于在 Qt Quick 中注册扩展 QML 类型的函数。它可以让你将自定义的 C++ 类型注册到 QML 中,以便在 QML 代码中使用这些类型。

  • T 是要注册的 C++ 类型。
  • uri 是类型的命名空间 URI。
  • majorVersionminorVersion 是版本号。
  • qmlName 是在 QML 中使用的类型名称。
  • templateArgs 是可选的模板参数(仅适用于模板类型)

代码演示:

cpp:

// customtype.h
#ifndef CUSTOMTYPE_H
#define CUSTOMTYPE_H

#include <QObject>

class CustomType : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)

public:
    explicit CustomType(QObject *parent = nullptr);

    int value() const;
    void setValue(int value);

signals:
    void valueChanged();

private:
    int m_value;
};

#endif // CUSTOMTYPE_H


//-------------------------------------------------------------------

// customtype.cpp
#include "customtype.h"

CustomType::CustomType(QObject *parent) : QObject(parent), m_value(0)
{}

int CustomType::value() const
{
    return m_value;
}

void CustomType::setValue(int value)
{
    if (m_value != value) {
        m_value = value;
        emit valueChanged();
    }
}

main函数中注册:

qmlRegisterExtendedType<CustomType>("CustomTypes", 1, 0, "CustomType", "int");

qml

// main.qml
import QtQuick 2.15
import CustomTypes 1.0

Rectangle {
    width: 200
    height: 200

    CustomType {
        id: customTypeObject
        value: 42
    }

    Text {
        anchors.centerIn: parent
        text: "Value: " + customTypeObject.value
    }
}

qmlRegisterExtendedUncreatableType

qmlRegisterExtendedUncreatableType() 是 Qt Quick 中用于注册扩展不可创建类型的函数。这种类型通常是一种特殊类型,它不能在 QML 中直接创建,但可以在 C++ 代码中创建并传递给 QML。

这个函数用于注册那些在 QML 中不能被实例化的类型,但可以在 C++ 中创建实例并通过指针传递给 QML。通常,这种类型用于在 QML 中表示一些特定的数据结构或对象,这些对象只能通过 C++ 代码创建,而不是在 QML 中实例化。

  • uri 是类型所在的命名空间。
  • versionMajorversionMinor 是类型的版本号。
  • qmlName 是在 QML 中使用的类型名称。
  • reason 是一个描述,用于说明为什么该类型不可创建。

代码:cpp文件:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QObject>

class MyExtendedType : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int value READ value CONSTANT)

public:
    MyExtendedType(QObject *parent = nullptr) : QObject(parent), m_value(42) {}

    int value() const { return m_value; }

private:
    int m_value;
};

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    qmlRegisterExtendedUncreatableType<MyExtendedType>("MyNamespace", 1, 0, "MyExtendedType", "You cannot create MyExtendedType objects from QML.");

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

#include "main.moc"

在这个示例中,我们定义了一个名为 MyExtendedType 的类,它继承自 QObject。我们使用 qmlRegisterExtendedUncreatableType() 函数将其注册到 QML 中。

在 QML 代码中,我们无法直接实例化 MyExtendedType,但是我们可以在 C++ 中创建它,并通过指针传递给 QML。这种类型在 QML 中通常用于表示一些数据模型或状态,这些对象只能在 C++ 代码中创建。

qml文件

import QtQuick 2.15
import MyNamespace 1.0

Item {
    Component.onCompleted: {
        var myObj = Qt.createQmlObject('import MyNamespace 1.0; MyExtendedType {}', parentItem, 'myObj');
        console.log(myObj.value);
    }
}

qmlRegisterInterface

qmlRegisterInterface() 是一个用于注册 QML 接口类型的函数。接口类型是一种特殊的类型,它定义了一组属性、方法或信号,但没有具体的实现。这些接口类型通常用于描述 QML 中的行为或功能,并且可以被其他 QML 类型实现。

  • uri 是接口类型所在的命名空间。
  • versionMajorversionMinor 是接口类型的版本号。
  • qmlName 是在 QML 中使用的接口类型的名称

cpp代码:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QObject>

class MyInterface : public QObject
{
    Q_OBJECT

public:
    virtual ~MyInterface() {}

    virtual void doSomething() = 0;
};

class MyImplementation : public MyInterface
{
    Q_OBJECT

public:
    void doSomething() override {
        qDebug() << "MyImplementation is doing something.";
    }
};

mian中:

qmlRegisterInterface<MyInterface>("MyNamespace", 1, 0, "MyInterface");

我们定义了一个名为 MyInterface 的接口类,并且使用 qmlRegisterInterface() 函数将其注册到 QML 中。然后,我们定义了一个实现了 MyInterface 接口的类 MyImplementation

在 QML 代码中,你可以将 MyInterface 用作其他 QML 类型的基类,并在具体的类型中实现 MyInterface 定义的方法。

qmlRegisterModule

qmlRegisterModule() 函数用于注册一个 QML 模块,使得该模块中的 QML 类型能够在 QML 中被访问和使用。

qml代码

import MyModule 1.0

Rectangle {
    width: 100
    height: 100
    color: "red"
    Text {
        anchors.centerIn: parent
        text: "Hello from MyModule!"
    }
}

qmlRegisterType

qmlRegisterType() 是一个用于在 Qt Quick 中注册自定义 QML 类型的函数。通过这个函数,你可以将自定义的 C++ 类型注册到 QML 中,使得你可以在 QML 代码中实例化和使用这些类型

代码cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QObject>

class MyCustomType : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

public:
    MyCustomType(QObject *parent = nullptr) : QObject(parent), m_name("John Doe") {}

    QString name() const { return m_name; }
    void setName(const QString &name) 
    {
        if (m_name != name) {
            m_name = name;
            emit nameChanged();
        }
    }

signals:
    void nameChanged();

private:
    QString m_name;
};

main中:

qmlRegisterType<MyCustomType>("com.example.customtype", 1, 0, "MyCustomType");

qml中

import QtQuick 2.15
import com.example.customtype 1.0

Item {
    MyCustomType {
        id: myCustomTypeObject
        name: "Alice"
    }

    Text {
        text: myCustomTypeObject.name
    }
}

qmlRegisterSingletonType

qmlRegisterSingletonType() 是用于注册单例类型到 QML 的函数。单例类型是指在 QML 中只能创建一个实例的类型。这些类型在整个 QML 应用程序中都是全局可访问的,可以用于共享全局状态、提供全局服务等

  • url 是单例类型的 QML 文件的 URL。
  • uri 是单例类型所在的命名空间。
  • versionMajorversionMinor 是单例类型的版本号。
  • qmlName 是在 QML 中使用的类型名称

cpp代码:

#include <QQmlContext>
#include <QObject>

class MySingletonType : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

public:
    MySingletonType(QObject *parent = nullptr) : QObject(parent), m_name("Singleton Object") {}

    QString name() const { return m_name; }
    void setName(const QString &name) {
        if (m_name != name) {
            m_name = name;
            emit nameChanged();
        }
    }

signals:
    void nameChanged();

private:
    QString m_name;
};

main中:

    qmlRegisterSingletonType<MySingletonType>("com.example.singleton", 1, 0, "MySingletonType", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
        Q_UNUSED(engine)
        Q_UNUSED(scriptEngine)

        return new MySingletonType();
    });

qml中:

import QtQuick 2.15
import com.example.singleton 1.0

Text {
    text: MySingletonType.name
}

qmlRegisterUncreatableType

qmlRegisterUncreatableType() 函数用于在 Qt Quick 中注册一个不可创建的类型,也就是说,这种类型在 QML 中不能通过 createComponent() 或者 createObject() 函数来创建实例。通常,这样的类型用于表示一些静态数据或者只能在 C++ 端创建的对象

  • uri 是类型所在的命名空间。
  • versionMajorversionMinor 是类型的版本号。
  • qmlName 是在 QML 中使用的类型名称。
  • reason 是一个描述,用于说明为什么该类型不可创建。

cpp函数

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QObject>

class MyUncreatableType : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString reason READ reason CONSTANT)

public:
    MyUncreatableType(QObject *parent = nullptr) : QObject(parent) {}

    QString reason() const { return m_reason; }

private:
    QString m_reason = "This type cannot be created from QML.";
};

main中:

    qmlRegisterUncreatableType<MyUncreatableType>("com.example.uncreatable", 1, 0, "MyUncreatableType", "This type cannot be created from QML.");

qml中

在 QML 代码中,你不能像普通类型一样使用 MyUncreatableType,因为它不能被创建。但是你可以访问它的属性或方法。

附上一个画框中随机点小星星的qml代码

直接当成文件,导入即可

import QtQuick

Item {
    anchors.fill: parent
    Rectangle {
        anchors.fill: parent
        color: "lightgray"
        MouseArea {
            anchors.fill: parent
            onClicked: {
                // 创建一个 rectangleComponent 定义的组件实例,并将其添加为 parent 元素的子组件
                var rectangle = rectangleComponent.createObject(parent)
                rectangle.x = mouseX
                rectangle.y = mouseY

                // [] qt5
                // rectangle.x = mouse.x
                // rectangle.y = mouse.y
                // []
            }
        }
    }
    Component {
        id: rectangleComponent
        Rectangle {
                width: 20; height: 20
                color: "lightgray"

                Canvas {
                    anchors.fill: parent
                    onPaint: {
                        // getContext 获取绘画环境,类似于HTML
                        var ctx = getContext("2d");
                        ctx.strokeStyle = "blue";
                        ctx.lineWidth = 2;

                        // 中心点
                        var centerX = width / 2;
                        var centerY = height / 2;

                        // 外接圆半径
                        var radius = Math.min(width, height) / 3;

                        ctx.beginPath();
                        for (var i = 0; i < 5; i++) {
                            // 计算顶点坐标
                            var theta = i * (Math.PI * 2) / 5 - Math.PI / 10;
                            var x = centerX + Math.cos(theta) * radius;
                            var y = centerY + Math.sin(theta) * radius;

                            if (i === 0) {
                                ctx.moveTo(x, y);
                            } else {
                                ctx.lineTo(x, y);
                            }
                        }
                        ctx.closePath();
                        ctx.stroke();
                    }
                }
            }
    }

}

一个GridView的绘制图

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

GridView {
    id: gridView
    anchors.fill: parent
    cellWidth: 100
    cellHeight: 100
    model: 20

    delegate: Item {
        width: gridView.cellWidth - 5
        height: gridView.cellHeight - 5

        Rectangle {
            anchors.fill: parent
            // color: "lightblue"
            border.color: "red"
            // Text {
            //     anchors.centerIn: parent
            //     text: index
            // }
        }
        // 在第三个项中插入按钮
        Button {
            visible: index === 2
            width: parent.width - 10
            height: deviceSize(parent.height)

            anchors.centerIn: parent.Center
            text: "Button"
            onClicked: console.log("Button clicked")
        }
        function deviceSize(size) {
            if (size > 30) {
                return 50
            } else {
                return parent.height
            }
        }

        // 在第六个项中插入下拉框
        ComboBox {
            visible: index === 5
            width: parent.width
            height: deviceComboxSize(parent.height)
            model: ["Option 1", "Option 2", "Option 3"]
        }
        function deviceComboxSize(size) {
            if (size > 30) {
                return 30
            } else {
                return parent.height
            }
        }
    }
}

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值