I am experiencing an odd issue accessing QVariantLists consisting of Q_GADGET objects via Q_PROPERTY's in another Q_GADGET object. For some reason, when accessing them through the property the lists nests itself down two elements like so:
Variable watch screenshot
Here is a small but working example that illustrates the issue I'm experiencing.
App class:
#pragma once
#include <QObject>
#include "Data.h"
class App : public QObject
{
public:
explicit App( QObject* parent = nullptr );
public slots:
void getData() const;
signals:
void dataReady( const Data& data ) const;
private:
Q_OBJECT
};
#include "App.h"
App::App( QObject* parent )
{
}
void App::getData() const
{
emit dataReady( Data() );
}
Data class:
#pragma once
#include <QObject>
#include <QVariant>
#include "Stats.h"
class Data
{
public:
Data();
Data( const Data& data );
~Data() = default;
public slots:
QList< QVariant > getStats() const;
private:
Q_GADGET
Q_PROPERTY( QList< QVariant > stats READ getStats CONSTANT )
QList< QVariant > stats;
void fillStats();
};
Q_DECLARE_METATYPE(Data)
#include "Stats.h"
#include "Data.h"
Data::Data()
{
fillStats();
}
Data::Data( const Data& data ) :
stats{ data.stats }
{
}
void Data::fillStats()
{
for ( int i = 0; i < 10; i++ )
stats.append( QVariant::fromValue( Stats( i ) ) );
}
QList< QVariant > Data::getStats() const
{
return stats;
}
Stats class:
#pragma once
#include <QObject>
class Stats
{
public:
Stats() = default;
Stats( int val );
Stats( const Stats& stats );
~Stats() = default;
public slots:
int getValue() const;
private:
Q_GADGET
Q_PROPERTY( int value READ getValue CONSTANT )
int value;
};
Q_DECLARE_METATYPE(Stats)
#include "Stats.h"
Stats::Stats(const Stats& stats) :
value{ stats.value }
{
}
Stats::Stats(int val) :
value{ val }
{
}
int Stats::getValue() const
{
return value;
}
main.cpp:
#include <QGuiApplication>
#include <QMetaType>
#include <QQmlApplicationEngine>
#include "App.h"
#include "Stats.h"
#include "Data.h"
int main( int argc, char* argv[] )
{
QGuiApplication app( argc, argv );
QQmlApplicationEngine engine;
qRegisterMetaType< Data >( "Data" );
qRegisterMetaType< Stats >( "Stats" );
qmlRegisterType< App >( "Test", 1, 0, "App" );
engine.load( QUrl( QStringLiteral( "qrc:/main.qml" ) ) );
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml:
import QtQuick 2.6
import QtQuick.Window 2.2
import Test 1.0
Window
{
visible: true
width: Screen.width
height: Screen.height
title: qsTr("Hello World")
Component.onCompleted: app.getData()
App
{
id: app
}
Connections
{
target: app
onDataReady: iterateThroughData( data )
}
function iterateThroughData( data )
{
for ( var i = 0; i < data.stats.length; i++ )
console.log( "broken here... somehow gets nested." );
}
}
Now, if you place a breakpoint on the following line in main.qml:
for ( var i = 0; i < data.stats.length; i++ )
In the watch window you will see how it somehow gets nested in two other single element lists.
Now if I change the signal to emit the list instead of the object, the list is completely normal and not nested.
Anyone ever run into this or see anything obvious I might be doing to cause this? Thanks. Sorry for so much code, this was the smallest working example I could make.