我编写了一个向 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。
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
属性对于序列化/反序列化工作流程非常有用,特别是当您在应用程序运行之间保留对象状态时。