Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Writing property that contains QList (problem converting to QVariant)
Forum Updated to NodeBB v4.3 + New Features

Writing property that contains QList (problem converting to QVariant)

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 4 Posters 742 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    Lotte
    wrote on last edited by
    #1

    Hello,

    The following question applies to Qt 6. I'm trying to load properties from an xml file into a class using the QMetaProperty::write() function. To simplify the example I left out the xml part and just hardcoded some values that I would like to write to the properties in this class. I'm using QMetaProperty::write() instead of the set functions because it allows me to easily loop over all properties in a class. This works perfectly, except for two types: a list of a list of points (QList<QList<QPointF>>) and a list of rectangles (QList<QRectF>). Somehow Qt is unable to convert these types into a QVariant, even though I used Q_DECLARE_METATYPE(QList<QList<QPointF>>) and Q_DECLARE_METATYPE(QList<QRectF>). How can I solve this problem? Minimal example below.

    listexample.h

    #ifndef LISTEXAMPLE_H
    #define LISTEXAMPLE_H
    
    #include <QMetaProperty>
    #include <QRect>
    
    Q_DECLARE_METATYPE(QList<QList<QPointF>>);
    Q_DECLARE_METATYPE(QList<QRectF>);
    
    class ListExample : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QList<QList<QPointF>> series MEMBER m_series READ getSeries WRITE setSeries NOTIFY seriesChanged)
        Q_PROPERTY(QList<QRectF> axisLims MEMBER m_axisLims READ getAxisLims WRITE setAxisLims NOTIFY axisLimsChanged)
    
    public:
        explicit ListExample();
    
        QList<QList<QPointF>> m_series;
        QList<QRectF> m_axisLims;
    
        Q_INVOKABLE QList<QList<QPointF>> getSeries() const;
        Q_INVOKABLE void setSeries(const QList<QList<QPointF>> series);
        Q_INVOKABLE QList<QRectF> getAxisLims() const;
        Q_INVOKABLE void setAxisLims(const QList<QRectF> axisLims);
    
        Q_INVOKABLE void deserializeObject();
    
    signals:
        void seriesChanged(QList<QList<QPointF>> m_series);
        void axisLimsChanged(QList<QRectF> m_axisLims);
    };
    
    #endif // LISTEXAMPLE_H
    

    listexample.cpp

    #include "listexample.h"
    
    ListExample::ListExample() : QObject() { }
    
    QList<QList<QPointF>> ListExample::getSeries() const
    {
        return m_series;
    }
    
    void ListExample::setSeries(const QList<QList<QPointF>> series)
    {
        if (series == m_series) return;
        m_series = series;
        emit seriesChanged(m_series);
    }
    
    QList<QRectF> ListExample::getAxisLims() const
    {
        return m_axisLims;
    }
    
    void ListExample::setAxisLims(const QList<QRectF> axisLims)
    {
        if (axisLims == m_axisLims) return;
        m_axisLims = axisLims;
        emit axisLimsChanged(m_axisLims);
    }
    
    void ListExample::deserializeObject()
    {
        const QMetaObject* metaObject = this->metaObject();
        int numProperties = metaObject->propertyCount();
        for (int propertyNr=0; propertyNr<numProperties; propertyNr++)
        {
            QMetaProperty property = metaObject->property(propertyNr);
            QString propertyType = QString(property.typeName()).remove(" ");
            QVariant propertyValue; // Normally loaded from xml, but hardcoded for example
            if (propertyType == "QList<QList<QPointF>>")
            {
                QList<QList<QPointF>> series({{QPointF(1,2), QPointF(3,4)}, {QPointF(5,6), QPointF(7,8)}});
                propertyValue = QVariant(series); // DOES NOT COMPILE!
                propertyValue = series; // DOES NOT COMPILE!
            }
            else if (propertyType == "QList<QRectF>")
            {
                QList<QRectF> axisLims({QRectF(1,2,3,4), QRectF(5,6,7,8)});
                propertyValue = QVariant(axisLims); // DOES NOT COMPILE!
                propertyValue = axisLims; // DOES NOT COMPILE!
            }
            if (!property.write(this, propertyValue))
            {
                QString propertyName(property.name());
                QString className(metaObject->className());
                qDebug() << "Unable to write property " + propertyName + " to class " + className;
            }
        }
    }
    

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
    
    project(listexample)
    
    set(CMAKE_INCLUDE_CURRENT_DIR ON)
    
    set(CMAKE_AUTOUIC ON)
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)
    
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    find_package(Qt6 REQUIRED COMPONENTS Core)
    
    add_executable(listexample ${GUI_TYPE} listexample.h listexample.cpp)
    
    target_compile_definitions(listexample PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
    
    target_link_libraries(listexample PRIVATE Qt${QT_VERSION_MAJOR}::Core)
    
    1 Reply Last reply
    0
    • I Offline
      I Offline
      ivan.solovev
      wrote on last edited by
      #6

      @Lotte said in Writing property that contains QList (problem converting to QVariant):

      propertyValue = QVariant(series); // DOES NOT COMPILE!

      Hi.
      This would not compile because QVariant does not have a constructor overload that takes a QList<QList<QPoint>> or QList<QRectF> as a parameter.

      I believe you need to do like that:

      propertyValue = QVariant::fromValue(series);
      

      Also, as mentioned above, consider passing parameters to the setter methods by constant reference, i.e.:

      Q_INVOKABLE void setAxisLims(const QList<QRectF> &axisLims); // note the '&'
      
      1 Reply Last reply
      1
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #2

        Hi and welcome to devnet,

        Did you register them as well ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        0
        • L Offline
          L Offline
          Lotte
          wrote on last edited by
          #3

          Adding the following two lines to the ListExample constructor does not seem to make a difference. Code still does not compile. Any suggestions are very welcome...

          qRegisterMetaType<QList<QList<QPointF>>>("QList<QList<QPointF>>");
          qRegisterMetaType<QList<QRectF>>("QList<QList<QPointF>>");
          
          JonBJ 1 Reply Last reply
          0
          • L Lotte

            Adding the following two lines to the ListExample constructor does not seem to make a difference. Code still does not compile. Any suggestions are very welcome...

            qRegisterMetaType<QList<QList<QPointF>>>("QList<QList<QPointF>>");
            qRegisterMetaType<QList<QRectF>>("QList<QList<QPointF>>");
            
            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by
            #4

            @Lotte
            Hi there. This may be totally unrelated to your current problem, so you may choose to ignore it for now. I also don't know anything about QML. But your definitions like:

            void ListExample::setSeries(const QList<QList<QPointF>> series)
            {
                if (series == m_series) return;
            

            Because you have not used any &s for "reference" in QList<QList<QPointF>> series that means it will copy the QList<QList<QPointF>> passed in. And so even if you pass in m_series as actual parameter I believe if (series == m_series) will never be true. (You could check this to verify if I am correct.) Efficiency-wise you might want to rethink your parameter type here and in setAxisLims() etc.

            1 Reply Last reply
            0
            • L Offline
              L Offline
              Lotte
              wrote on last edited by
              #5

              @JonB Thanks for the reply. I tested your suggestion by adding the following 2 functions to the ListExample class.

              void ListExample::compareSeries(const QList<QList<QPointF>> series1, const QList<QList<QPointF>> series2)
              {
                  if (series1 == series2) qDebug() << "series are the same";
                  else qDebug() << "series are different";
              }
              
              void ListExample::runTest()
              {
                  QList<QList<QPointF>> seriesA({{QPointF(1,2), QPointF(3,4)}, {QPointF(5,6), QPointF(7,8)}});
                  QList<QList<QPointF>> seriesB({{QPointF(1,2), QPointF(3,4)}, {QPointF(5,6), QPointF(7,8)}});
                  QList<QList<QPointF>> seriesC({{QPointF(8,7), QPointF(6,5)}, {QPointF(4,3), QPointF(2,1)}});
                  compareSeries(seriesA, seriesB);
                  compareSeries(seriesA, seriesC);
                  compareSeries(seriesB, seriesC);
              }
              

              The output for runTest() is:

              series are the same
              series are different
              series are different
              

              So the check in if (series == m_series) seems to be working correctly. However, the code still does not compile when uncommenting the problematic lines

              propertyValue = QVariant(series); // DOES NOT COMPILE!
              propertyValue = series; // DOES NOT COMPILE!
              

              and

              propertyValue = QVariant(axisLims); // DOES NOT COMPILE!
              propertyValue = axisLims; // DOES NOT COMPILE!
              

              Any more ideas? I'm completely stuck so anything is welcome!

              JonBJ 1 Reply Last reply
              0
              • I Offline
                I Offline
                ivan.solovev
                wrote on last edited by
                #6

                @Lotte said in Writing property that contains QList (problem converting to QVariant):

                propertyValue = QVariant(series); // DOES NOT COMPILE!

                Hi.
                This would not compile because QVariant does not have a constructor overload that takes a QList<QList<QPoint>> or QList<QRectF> as a parameter.

                I believe you need to do like that:

                propertyValue = QVariant::fromValue(series);
                

                Also, as mentioned above, consider passing parameters to the setter methods by constant reference, i.e.:

                Q_INVOKABLE void setAxisLims(const QList<QRectF> &axisLims); // note the '&'
                
                1 Reply Last reply
                1
                • L Lotte

                  @JonB Thanks for the reply. I tested your suggestion by adding the following 2 functions to the ListExample class.

                  void ListExample::compareSeries(const QList<QList<QPointF>> series1, const QList<QList<QPointF>> series2)
                  {
                      if (series1 == series2) qDebug() << "series are the same";
                      else qDebug() << "series are different";
                  }
                  
                  void ListExample::runTest()
                  {
                      QList<QList<QPointF>> seriesA({{QPointF(1,2), QPointF(3,4)}, {QPointF(5,6), QPointF(7,8)}});
                      QList<QList<QPointF>> seriesB({{QPointF(1,2), QPointF(3,4)}, {QPointF(5,6), QPointF(7,8)}});
                      QList<QList<QPointF>> seriesC({{QPointF(8,7), QPointF(6,5)}, {QPointF(4,3), QPointF(2,1)}});
                      compareSeries(seriesA, seriesB);
                      compareSeries(seriesA, seriesC);
                      compareSeries(seriesB, seriesC);
                  }
                  

                  The output for runTest() is:

                  series are the same
                  series are different
                  series are different
                  

                  So the check in if (series == m_series) seems to be working correctly. However, the code still does not compile when uncommenting the problematic lines

                  propertyValue = QVariant(series); // DOES NOT COMPILE!
                  propertyValue = series; // DOES NOT COMPILE!
                  

                  and

                  propertyValue = QVariant(axisLims); // DOES NOT COMPILE!
                  propertyValue = axisLims; // DOES NOT COMPILE!
                  

                  Any more ideas? I'm completely stuck so anything is welcome!

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by
                  #7

                  @Lotte said in Writing property that contains QList (problem converting to QVariant):

                  So the check in if (series == m_series) seems to be working correctly.

                  Just on that one. I forgot that QList has Qt's only-copy-on-write semantics, hence why it works.
                  But agree this is not related to your issue anyway.

                  1 Reply Last reply
                  0
                  • L Offline
                    L Offline
                    Lotte
                    wrote on last edited by Lotte
                    #8

                    Thank you @ivan-solovev for the answer! It works!

                    1 Reply Last reply
                    0

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved