I wrote a code which exposes an C++ object to QML and I would like to check declared properties of the object with native JS things, but they does not work as it expected. I wrote FizzBuzzDerived.properties
method and it works file as I would expect Object.keys
work.
Result in case of calling the functions
Object.keys(FizzBuzz); // -> []
Object.values(FizzBuzz); // -> []
JSON.stringify(FizzBuzz); // -> {}
FizzBuzz.properties(); // -> ["objectName", "fizz", "buzz", "foo", "bar"]
Here is the code.
main.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
objectstorage.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
fizzbuzzderived.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
fizzbuzzderived.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(", "));
}
}
Tried to get the object keys from C++ side and it works.
Don’t have a clue why this is happening.