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)
Qt 6.11 is out! See what's new in the release blog

Writing property that contains QList (problem converting to QVariant)

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 4 Posters 1.2k 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