0

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.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Eventh
  • 21
  • 2
  • 7

1 Answers1

0

The problem is caused by wanting to copy the list with the following line of code:

Data::Data( const Data& data ):
    stats{data.stats} 
    // Is similar to stats << data.stats or stats.append(data.stats)
{
}

To be stats a QList when using {} you are adding an item, that is another stats to the existing stats, what you must do is to use the copy constructor of QList:

Data::Data( const Data& data ):
    stats(data.stats)
{
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241