当从 QML 中的 Q_PROPERTY 访问时,QVariantList 变得嵌套

QVariantList becomes nested when accessed from Q_PROPERTY in QML

我在通过另一个 Q_GADGET 对象中的 Q_PROPERTY 访问由 Q_GADGET 对象组成的 QVariantLists 时遇到一个奇怪的问题。出于某种原因,当通过 属性 访问它们时,列表将自己嵌套在两个元素下,如下所示:

可变手表截图

这是一个小但有效的示例,它说明了我遇到的问题。

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

数据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;
}

统计数据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." );
   }
}

现在,如果您在 main.qml 中的以下行放置断点:

for ( var i = 0; i < data.stats.length; i++ )

在手表 window 中,您将看到它如何以某种方式嵌套在另外两个单个元素列表中。

现在,如果我更改信号以发出列表而不是对象,则列表是完全正常的并且没有嵌套。

任何人曾经 运行 进入这个或看到任何明显的我可能会导致这个的事情吗?谢谢。抱歉,代码太多,这是我能做的最小的工作示例。

问题是由于想用下面一行代码复制列表造成的:

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

要在使用 {} 时成为 stats QList,您正在添加一个项目,即现有统计数据的另一个统计数据,您必须做的是使用 copy constructor of QList

Data::Data( const Data& data ):
    stats(data.stats)
{
}