Object.keys、Object.values 和 JSON.stringify 在 QML 中给出空结果

问题描述 投票:0回答:1

我编写了一个向 QML 公开 C++ 对象的代码,我想使用本机 JS 事物检查该对象的声明属性,但它们没有按预期工作。我编写了

FizzBuzzDerived.properties
方法,它的工作文件正如我所期望的
Object.keys
工作。

调用函数时的结果

Object.keys(FizzBuzz);    // -> []
Object.values(FizzBuzz);  // -> []
JSON.stringify(FizzBuzz); // -> {} 
FizzBuzz.properties();    // -> ["objectName", "fizz", "buzz", "foo", "bar"]

这是代码。

主.cpp

#include "myplugin.h"
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlEngine>
#include <QQmlExtensionPlugin>

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

    MyPlugin plugin;
    plugin.registerTypes("ObjectStorage");

    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();
}

myplugin.h

#ifndef MYPLUGIN_H
#define MYPLUGIN_H

#include "objectstorage.h"
#include <QObject>
#include <QQmlExtensionPlugin>

class MyPlugin : public QQmlExtensionPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
    void registerTypes(const char *uri) override
    {
        Q_ASSERT(QLatin1String(uri) == QLatin1String("ObjectStorage"));
        qmlRegisterSingletonType<FizzBuzzDerived>("Model", 1, 0, "FizzBuzz", ObjectStorage::provider);
    }
};

#endif // MYPLUGIN_H

对象存储.h

#ifndef OBJECTSTORAGE_H
#define OBJECTSTORAGE_H

#include "fizzbuzzderived.h"
#include <QObject>
#include <QQmlEngine>

class ObjectStorage : public QObject
{
    Q_OBJECT
public:
    static QObject *provider(QQmlEngine *qml, QJSEngine *js)
    {
        Q_UNUSED(qml)
        Q_UNUSED(js)

        FizzBuzzDerived *object = new FizzBuzzDerived();
        object->setFizz(45);
        object->setBuzz(24.42);
        object->setFoo(false);
        object->setBar(Bar::B);

        return object;
    }
};

#endif // OBJECTSTORAGE_H

fizzbuzz衍生.h

#ifndef FIZZBUZZDERIVED_H
#define FIZZBUZZDERIVED_H

#include "fizzbuzz.h"
#include <QObject>
#include <QDebug>

class FizzBuzzDerived : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int fizz READ fizz WRITE setFizz NOTIFY fizzChanged);
    Q_PROPERTY(double buzz READ buzz WRITE setBuzz NOTIFY buzzChanged)
    Q_PROPERTY(bool foo READ foo WRITE setFoo NOTIFY fooChanged)
    Q_PROPERTY(int bar READ bar WRITE setBar NOTIFY barChanged)

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

    Q_INVOKABLE QList<QString> properties() const;

    int fizz() const;
    double buzz() const;
    bool foo() const;
    int bar() const;

public slots:
    void setFizz(int fizz);
    void setBuzz(double buzz);
    void setFoo(bool foo);
    void setBar(int bar);

signals:
    void fizzChanged(int fizz);
    void buzzChanged(double buzz);
    void fooChanged(bool foo);
    void barChanged(int bar);

private:
    FizzBuzz m_object;
};

Q_DECLARE_METATYPE(FizzBuzzDerived *)

#endif // FIZZBUZZDERIVED_H

fizzbuzz衍生.cpp

#include "fizzbuzzderived.h"
#include <QMetaProperty>

FizzBuzzDerived::FizzBuzzDerived(QObject *parent)
    : QObject(parent)
{

}

QList<QString> FizzBuzzDerived::properties() const
{
    QList<QString> names;
    const QMetaObject *metaObject = this->metaObject();
    for (int i = 0; i < metaObject->propertyCount(); ++i) {
        QMetaProperty property = metaObject->property(i);
        names << QString(property.name());
    }

    return names;
}

int FizzBuzzDerived::fizz() const
{
    return m_object.fizz;
}

double FizzBuzzDerived::buzz() const
{
    return m_object.buzz;
}

bool FizzBuzzDerived::foo() const
{
    return m_object.foo;
}

int FizzBuzzDerived::bar() const
{
    return m_object.bar;
}

void FizzBuzzDerived::setFizz(int fizz)
{
    if (m_object.fizz != fizz) {
        m_object.fizz = fizz;
        emit fizzChanged(m_object.fizz);
    }
}

void FizzBuzzDerived::setBuzz(double buzz)
{
    if (m_object.buzz != buzz) {
        m_object.buzz = buzz;
        emit buzzChanged(m_object.buzz);
    }
}

void FizzBuzzDerived::setFoo(bool foo)
{
    if (m_object.foo != foo) {
        m_object.foo = foo;
        emit fooChanged(m_object.foo);
    }
}

void FizzBuzzDerived::setBar(int bar)
{
    if (m_object.bar != bar) {
        m_object.bar = static_cast<Bar>(bar);
        emit barChanged(m_object.bar);
    }
}

main.qml

import QtQuick 2.0
import Model 1.0

Item {
    property FizzBuzz item: FizzBuzz

    Component.onCompleted: {
        const object = item;
        const props = object.properties();
        console.info(`object: ${object}`)
        console.info(props.map(prop => `${prop}: ${JSON.stringify(object[prop])}`).join(", "));
    }
}

尝试从 C++ 端获取对象键并且它有效。 不知道为什么会发生这种情况。

顺便说一下,我使用的是Qt 5.14.2。

javascript json qt qml
1个回答
0
投票

QObject、QML 对象、JavaScript 对象不是同一件事。

在可能的情况下,Qt 会尽最大努力将对象从一种格式映射到另一种格式,但在这种情况下它将不起作用。例如,Qt 将为您映射一个 QVariant,特别是 QVariantMap 到 JavaScript。因此,如果您可以将属性编组到 QVariantMap 中,Qt 将处理其余的事情,例如

    Q_PROPERTY(QVariant json READ getJson WRITE setJson NOTIFY jsonChanged);

    signals jsonChanged();

    QVariant getJson() const
    {
        QVariantMap obj = new QVariantMap();
        obj["fizz"] = fizz();
        // ... repeat for your other properties
        return obj;
    }

    void setJson(const QVariant& obj)
    {
         // TODO: add guards to check obj is a QVariantMap
         QVariantMap map = obj.toMap();
         setFizz(map["fizz"].toInt());
         // TODO: repeat for other properties, also proper type checking and guards are needed
    }

然后在 QML/JS 中,您可以在返回的

QVariantMap
上使用 JavaScript 方法,即

Object.keys(FizzBuzz.json);
Object.values(FizzBuzz.json);
JSON.stringify(FizzBuzz.json);

json
属性对于序列化/反序列化工作流程非常有用,特别是当您在应用程序运行之间保留对象状态时。

© www.soinside.com 2019 - 2024. All rights reserved.