如果自定义类型从 C++ 作为 const 传递,如何使用 QML 注册自定义类型

Posted

技术标签:

【中文标题】如果自定义类型从 C++ 作为 const 传递,如何使用 QML 注册自定义类型【英文标题】:How to register custom type with QML if it is passed as const from C++ 【发布时间】:2018-10-12 16:38:17 【问题描述】:

我有一个名为 MyClass 的 C++ 类。该类注册为不可创建类型,因此可以在 QML 中按名称引用。

MyClass.h:

#pragma once

#include <QObject>

class MyClass : public QObject 
Q_OBJECT

public:
    static void initQML();

    MyClass();
    MyClass(const MyClass &myClass);
    ~MyClass();

    Q_INVOKABLE void printText();
;

MyClass.cpp:

#include "MyClass.h"

#include <QtQml>
#include <QDebug>
#include <QMetaType>

/*static*/ void MyClass::initQML() 
    qmlRegisterUncreatableType<const MyClass>("Test", 1, 0, "MyClass", "Don't create it");

    qRegisterMetaType<const MyClass*>("const MyClass*");


MyClass::MyClass() 
    qDebug() << "Constructor called.";


MyClass::MyClass(const MyClass &myClass) 
    qDebug() << "Copy constructor called.";


MyClass::~MyClass() 
    qDebug() << "Destructor called.";


void MyClass::printText() 
    qDebug() << "This a sample text.";

我有另一个班级,叫做MyClassFactory。此类创建MyClass 对象。它作为单例类型注册到 QML。

MyClassFactory.h:

#pragma once

#include "MyClass.h"

#include <QObject>

class MyClassFactory : public QObject 
Q_OBJECT

public:
    static void initQML();

    MyClassFactory();

public slots:
    static const MyClass *makeDefaultMyClass();
;

MyClassFactory.cpp:

#include "MyClassFactory.h"

#include <QtQml>
#include <QQmlEngine>
#include <QJSEngine>

QObject *simpleQmlRegisterSingletonTypeCallback(QQmlEngine *, QJSEngine *) 
    return new MyClassFactory();


/*static*/ void MyClassFactory::initQML() 
    qmlRegisterSingletonType<MyClassFactory>("Test", 1, 0, "MyClassFactory",
                                             simpleQmlRegisterSingletonTypeCallback);


MyClassFactory::MyClassFactory() 

/*static*/ const MyClass* MyClassFactory::makeDefaultMyClass() 
    return new MyClass();

在我的main.qml 中,我创建了一个MyClass 类型的属性并通过MyClassFactory 将一个值绑定到它。这是我的main.qml

import QtQuick 2.9
import QtQuick.Controls 2.2

import Test 1.0

ApplicationWindow 
    visible: true

    width: 480
    height: 272

    property MyClass myClass: MyClassFactory.makeDefaultMyClass()

    Button 
        anchors.centerIn: parent

        text: "Create MyClass"

        onClicked: myClass.printText()
    

当我构建并运行我的代码时,我在控制台中收到以下错误:

qrc:/main.qml:12: Error: Unknown method return type: const MyClass*

如果我将const MyClass* 注册为元类型,则此错误消失,但我得到另一个错误:

qrc:/main.qml:12:31: Unable to assign const MyClass* to MyClass*

首先,如果我已经将 const MyClass 注册为 QML(不可创建)类型,为什么还要将 const MyClass* 注册为元类型?

主要问题是如何将 const 指针传递给 QML?

对于一个完整的运行示例,这是我的main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include "MyClass.h"
#include "MyClassFactory.h"

int main(int argc, char *argv[])

    QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    // Init

    MyClass::initQML();
    MyClassFactory::initQML();

    // Main loop

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();

我使用 Qt 5.9.5。

【问题讨论】:

为什么不直接通过MyClass 而不是const MyClass 我可以通过MyClass 而不是const MyClass,这就是我目前正在做的事情,但我想学习如何使用const 或者如果不可能做到这一点const,那为什么? 【参考方案1】:

你得到的错误清楚地表明它不会与const 一起工作,无论如何你扭曲它,因为这不是 API 的设计方式,因为虽然你可以将非 const 对象传递给 const 函数,但你出于显而易见的原因,不能做相反的事情。而且,至少在您使用的 Qt 版本中,这个特定的 API 将具有 const 正确的一面并没有多大意义。

直到最近,JS 还没有真正意义上的常量。它是在 ECMA 2015 中引入的,但目前 QML 仍然不支持该规范。 Qt 5.12 将实现它,但即便如此,我怀疑它是否会从一开始就与 C++ 方面集成。正确传播 const 正确性将是一件好事,但话又说回来,看到空指针变体如何仍然通过 QML 中的if 检查,我不会屏住呼吸......

存在只读属性的概念,但这和常量真的不一样,只是属性不能被赋予不同的值,如果值恰好是一个对象,它仍然可以被修改。

因此,如果您希望它成为一个常量,最简单的做法是简单地公开一个接口来对该对象进行更改。

此外,如果您对这些类型使用qmlRegisterUncreatableType()qmlRegisterType()qmlRegisterSingletonType() 或类似类型,则无需注册QObject 派生类型指针。

【讨论】:

非常感谢@dtech 的解释。我有这种感觉,但我想对此有额外的意见。 @dtech,你能看看this question我想知道你是否曾经以不同的方式解决它。

以上是关于如果自定义类型从 C++ 作为 const 传递,如何使用 QML 注册自定义类型的主要内容,如果未能解决你的问题,请参考以下文章

继承自作为模板参数传递的const类型

将数组作为 C++ 中方法的 const 参数传递

高质量C++读书笔记(复习用)

如何使 const 适用于作为共享指针的 C++ 类成员

Postgres:将自定义类型从 Java 传递给 postgres 函数

Qt 使用自定义 QObject 类型调用 qml 函数