Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Return type constant properties
Forum Updated to NodeBB v4.3 + New Features

Return type constant properties

Scheduled Pinned Locked Moved Solved QML and Qt Quick
6 Posts 2 Posters 964 Views
  • 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.
  • M Offline
    M Offline
    michjans
    wrote on last edited by
    #1

    Hello,
    I have the following class, that I am exposing to QML.

    class RecipeBackEnd : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QStringListModel recipes READ recipes CONSTANT)
        QML_ELEMENT
    
    public:
        explicit RecipeBackEnd(QObject *parent = nullptr);
    
        const QStringListModel *recipes() const
        {
            return &m_recipeList;
        }
    
    private:
        QStringListModel m_recipeList;
    };
    

    The class itself is registered correctly, but I cannot access it's property.

    I get the following QML error:
    QMetaProperty::read: Unable to handle unregistered datatype 'QStringListModel' for property 'RecipeBackEnd::recipes'

    I also tried setting the property type to a const QStringListModel *:

    Q_PROPERTY(const QStringListModel * recipes READ recipes CONSTANT)
    

    but it results in the same error for a const QStringListModel *.

    I want it to return a QStringListModel that I can show in a QML ListView. I am not allowed (and I don't want to) make a copy of the QStringListModel. The model itself never changes runtime, so I made it a CONSTANT property with only a READ method.

    Can anyone tell me what I am doing wrong?

    Thanks!

    eyllanescE 1 Reply Last reply
    0
    • M Offline
      M Offline
      michjans
      wrote on last edited by
      #4

      I've experimented some more, but still haven't got it working.

      I tried making the recipes method invokable by prefixing it with Q_INVOKABLE. But then when calling this method from QML, I get the error that const QStringListModel * is not recognized.

      Then I tried setting the property explicitly from within C++, using:

      QObject::setProperty("recipes", QVariant::fromValue(m_recipeList)
      

      but still getting the property as undefined.

      I assume my problem was that I was instantiating the QStringListModel from c++ and then try to return it to QML using a property. I had the feeling that this is the wrong approach.

      So, I tried creating a class RecipeList derived from QStringListModel and register that class as QML type:

      class RecipeList : public QStringListModel
      {
          Q_OBJECT
          QML_ELEMENT
      
      public:
          explicit RecipeList(QObject *parent = nullptr);
      };
      
      //cpp implementation
      RecipeList::RecipeList(QObject *parent) : QStringListModel(parent)
      {
          setStringList(QStringList() << "item1" << "item2");
      }
      

      Then created the ListView in QML and assigned my registered class as model, like this:

      ListView {
             anchors.fill: parent
             model: RecipeList {}
             delegate: Rectangle {
                 height: 50
                 width: 100
                 Text { text: modelData }
             }
         }
      

      I see no QML errors anymore, but unfortunately the list still remains empty.

      eyllanescE 1 Reply Last reply
      0
      • M michjans

        Hello,
        I have the following class, that I am exposing to QML.

        class RecipeBackEnd : public QObject
        {
            Q_OBJECT
            Q_PROPERTY(QStringListModel recipes READ recipes CONSTANT)
            QML_ELEMENT
        
        public:
            explicit RecipeBackEnd(QObject *parent = nullptr);
        
            const QStringListModel *recipes() const
            {
                return &m_recipeList;
            }
        
        private:
            QStringListModel m_recipeList;
        };
        

        The class itself is registered correctly, but I cannot access it's property.

        I get the following QML error:
        QMetaProperty::read: Unable to handle unregistered datatype 'QStringListModel' for property 'RecipeBackEnd::recipes'

        I also tried setting the property type to a const QStringListModel *:

        Q_PROPERTY(const QStringListModel * recipes READ recipes CONSTANT)
        

        but it results in the same error for a const QStringListModel *.

        I want it to return a QStringListModel that I can show in a QML ListView. I am not allowed (and I don't want to) make a copy of the QStringListModel. The model itself never changes runtime, so I made it a CONSTANT property with only a READ method.

        Can anyone tell me what I am doing wrong?

        Thanks!

        eyllanescE Offline
        eyllanescE Offline
        eyllanesc
        wrote on last edited by
        #2

        @michjans use Q_PROPERTY(QStringListModel * recipes READ recipes CONSTANT)
        or Q_PROPERTY(QAbstractListModel * recipes READ recipes CONSTANT)

        If you want me to help you develop some work then you can write to my email: e.yllanescucho@gmal.com.

        1 Reply Last reply
        0
        • M Offline
          M Offline
          michjans
          wrote on last edited by
          #3

          Thanks, but this results in a compiler error of the generated moc file:

          moc_recipebackend.cpp:89: error: invalid conversion from ‘const QStringListModel*’ to ‘QStringListModel*’ [-fpermissive]
          moc_recipebackend.cpp: In static member function ‘static void RecipeBackEnd::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)’:
          moc_recipebackend.cpp:89:73: error: invalid conversion from ‘const QStringListModel*’ to ‘QStringListModel*’ [-fpermissive]
                   case 0: *reinterpret_cast< QStringListModel**>(_v) = _t->recipes(); break;
                                                                        ~~~~~~~~~~~^~
          

          So, it seems that the type of the PROPERTY has to match the return type of the READ member.

          I, also tried your second suggestion:

          Q_PROPERTY(const QAbstractListModel * recipes READ recipes CONSTANT)
          

          But, this still results in a runtime QML error:

          QMetaProperty::read: Unable to handle unregistered datatype 'const QAbstractListModel' for property 'RecipeBackEnd::recipes'*

          1 Reply Last reply
          0
          • M Offline
            M Offline
            michjans
            wrote on last edited by
            #4

            I've experimented some more, but still haven't got it working.

            I tried making the recipes method invokable by prefixing it with Q_INVOKABLE. But then when calling this method from QML, I get the error that const QStringListModel * is not recognized.

            Then I tried setting the property explicitly from within C++, using:

            QObject::setProperty("recipes", QVariant::fromValue(m_recipeList)
            

            but still getting the property as undefined.

            I assume my problem was that I was instantiating the QStringListModel from c++ and then try to return it to QML using a property. I had the feeling that this is the wrong approach.

            So, I tried creating a class RecipeList derived from QStringListModel and register that class as QML type:

            class RecipeList : public QStringListModel
            {
                Q_OBJECT
                QML_ELEMENT
            
            public:
                explicit RecipeList(QObject *parent = nullptr);
            };
            
            //cpp implementation
            RecipeList::RecipeList(QObject *parent) : QStringListModel(parent)
            {
                setStringList(QStringList() << "item1" << "item2");
            }
            

            Then created the ListView in QML and assigned my registered class as model, like this:

            ListView {
                   anchors.fill: parent
                   model: RecipeList {}
                   delegate: Rectangle {
                       height: 50
                       width: 100
                       Text { text: modelData }
                   }
               }
            

            I see no QML errors anymore, but unfortunately the list still remains empty.

            eyllanescE 1 Reply Last reply
            0
            • M michjans

              I've experimented some more, but still haven't got it working.

              I tried making the recipes method invokable by prefixing it with Q_INVOKABLE. But then when calling this method from QML, I get the error that const QStringListModel * is not recognized.

              Then I tried setting the property explicitly from within C++, using:

              QObject::setProperty("recipes", QVariant::fromValue(m_recipeList)
              

              but still getting the property as undefined.

              I assume my problem was that I was instantiating the QStringListModel from c++ and then try to return it to QML using a property. I had the feeling that this is the wrong approach.

              So, I tried creating a class RecipeList derived from QStringListModel and register that class as QML type:

              class RecipeList : public QStringListModel
              {
                  Q_OBJECT
                  QML_ELEMENT
              
              public:
                  explicit RecipeList(QObject *parent = nullptr);
              };
              
              //cpp implementation
              RecipeList::RecipeList(QObject *parent) : QStringListModel(parent)
              {
                  setStringList(QStringList() << "item1" << "item2");
              }
              

              Then created the ListView in QML and assigned my registered class as model, like this:

              ListView {
                     anchors.fill: parent
                     model: RecipeList {}
                     delegate: Rectangle {
                         height: 50
                         width: 100
                         Text { text: modelData }
                     }
                 }
              

              I see no QML errors anymore, but unfortunately the list still remains empty.

              eyllanescE Offline
              eyllanescE Offline
              eyllanesc
              wrote on last edited by eyllanesc
              #5

              @michjans The role of a QStringListModel is "display" so you should not use modelData.

              On the other hand, I have used the option indicated in my previous comment and it works correctly for me (I recommend deleting the build folder)

              *.pro

              QT += quick
              CONFIG += c++11
              
              SOURCES += \
                      main.cpp \
                      recipebackend.cpp
              HEADERS += recipebackend.h
              RESOURCES += qml.qrc
              
              CONFIG += qmltypes
              QML_IMPORT_NAME = Recipe
              QML_IMPORT_MAJOR_VERSION = 1
              

              main.cpp

              #include <QGuiApplication>
              #include <QQmlApplicationEngine>
              
              int main(int argc, char *argv[])
              {
              #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
                  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
              #endif
              
                  QGuiApplication app(argc, argv);
              
                  QQmlApplicationEngine engine;
                  const QUrl url(QStringLiteral("qrc:/main.qml"));
                  QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                                   &app, [url](QObject *obj, const QUrl &objUrl) {
                      if (!obj && url == objUrl)
                          QCoreApplication::exit(-1);
                  }, Qt::QueuedConnection);
                  engine.load(url);
              
                  return app.exec();
              }
              

              recipebackend.h

              #ifndef RECIPEBACKEND_H
              #define RECIPEBACKEND_H
              
              #include <QObject>
              #include <qqml.h>
              #include <QStringListModel>
              
              class RecipeBackEnd : public QObject
              {
                  Q_OBJECT
                  Q_PROPERTY(QStringListModel* recipes READ recipes CONSTANT)
                  QML_ELEMENT
              
              public:
                  explicit RecipeBackEnd(QObject *parent = nullptr);
              
                  QStringListModel *recipes();
              
              private:
                  QStringListModel m_recipeList;
              };
              
              #endif // RECIPEBACKEND_H
              

              recipebackend.cpp

              #include "recipebackend.h"
              
              RecipeBackEnd::RecipeBackEnd(QObject *parent) : QObject(parent)
              {
                  m_recipeList.setStringList(QStringList() << "item1" << "item2");
              }
              
              QStringListModel *RecipeBackEnd::recipes()
              {
                  return &m_recipeList;
              }
              

              main.qml

              import QtQuick 2.12
              import QtQuick.Window 2.12
              
              import Recipe 1.0
              
              Window {
                  width: 640
                  height: 480
                  visible: true
                  title: qsTr("Hello World")
              
                  RecipeBackEnd{
                      id: backend
                  }
              
                  ListView {
                      anchors.fill: parent
                      model: backend.recipes
                      delegate: Rectangle {
                          height: 50
                          width: 100
                          Text { text: model.display }
                      }
                  }
              }
              

              qml.qrc

              <RCC>
                  <qresource prefix="/">
                      <file>main.qml</file>
                  </qresource>
              </RCC>
              

              Output:

              Screenshot_20201231_101644.png

              If you want me to help you develop some work then you can write to my email: e.yllanescucho@gmal.com.

              M 1 Reply Last reply
              0
              • eyllanescE eyllanesc

                @michjans The role of a QStringListModel is "display" so you should not use modelData.

                On the other hand, I have used the option indicated in my previous comment and it works correctly for me (I recommend deleting the build folder)

                *.pro

                QT += quick
                CONFIG += c++11
                
                SOURCES += \
                        main.cpp \
                        recipebackend.cpp
                HEADERS += recipebackend.h
                RESOURCES += qml.qrc
                
                CONFIG += qmltypes
                QML_IMPORT_NAME = Recipe
                QML_IMPORT_MAJOR_VERSION = 1
                

                main.cpp

                #include <QGuiApplication>
                #include <QQmlApplicationEngine>
                
                int main(int argc, char *argv[])
                {
                #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
                    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
                #endif
                
                    QGuiApplication app(argc, argv);
                
                    QQmlApplicationEngine engine;
                    const QUrl url(QStringLiteral("qrc:/main.qml"));
                    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                                     &app, [url](QObject *obj, const QUrl &objUrl) {
                        if (!obj && url == objUrl)
                            QCoreApplication::exit(-1);
                    }, Qt::QueuedConnection);
                    engine.load(url);
                
                    return app.exec();
                }
                

                recipebackend.h

                #ifndef RECIPEBACKEND_H
                #define RECIPEBACKEND_H
                
                #include <QObject>
                #include <qqml.h>
                #include <QStringListModel>
                
                class RecipeBackEnd : public QObject
                {
                    Q_OBJECT
                    Q_PROPERTY(QStringListModel* recipes READ recipes CONSTANT)
                    QML_ELEMENT
                
                public:
                    explicit RecipeBackEnd(QObject *parent = nullptr);
                
                    QStringListModel *recipes();
                
                private:
                    QStringListModel m_recipeList;
                };
                
                #endif // RECIPEBACKEND_H
                

                recipebackend.cpp

                #include "recipebackend.h"
                
                RecipeBackEnd::RecipeBackEnd(QObject *parent) : QObject(parent)
                {
                    m_recipeList.setStringList(QStringList() << "item1" << "item2");
                }
                
                QStringListModel *RecipeBackEnd::recipes()
                {
                    return &m_recipeList;
                }
                

                main.qml

                import QtQuick 2.12
                import QtQuick.Window 2.12
                
                import Recipe 1.0
                
                Window {
                    width: 640
                    height: 480
                    visible: true
                    title: qsTr("Hello World")
                
                    RecipeBackEnd{
                        id: backend
                    }
                
                    ListView {
                        anchors.fill: parent
                        model: backend.recipes
                        delegate: Rectangle {
                            height: 50
                            width: 100
                            Text { text: model.display }
                        }
                    }
                }
                

                qml.qrc

                <RCC>
                    <qresource prefix="/">
                        <file>main.qml</file>
                    </qresource>
                </RCC>
                

                Output:

                Screenshot_20201231_101644.png

                M Offline
                M Offline
                michjans
                wrote on last edited by
                #6

                @eyllanesc I took over your example into my project, deleted my build folder and rebuild my project again. After this it works correctly!

                I'm not exactly sure where it went wrong.

                Thanks for your help!

                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