Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct

    Solved QQmlListProperty is deprecated, but how to migrate?

    QML and Qt Quick
    3
    4
    642
    Loading More Posts
    • 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.
    • Y
      Yujeonja last edited by

      I have a project that extending QML using C++ which is using QQmlListProperty for default property. But from Qt 5.15 it complains deprecated warning.
      This is a minimal reproducing refer to this example. My project is very similar.

      // person.h
      #ifndef PERSON_H
      #define PERSON_H
      
      #include <QObject>
      
      class Person : public QObject
      {
          Q_OBJECT
      
          Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
      public:
          explicit Person(QObject *parent = nullptr);
      
          QString name() const;
          void setName(const QString& name);
      
      signals:
          void nameChanged(QString name);
      
      private:
          QString m_name;
      };
      
      #endif // PERSON_H
      
      // person.cpp
      #include "person.h"
      
      Person::Person(QObject *parent) : QObject(parent)
      {
      
      }
      
      QString Person::name() const
      {
          return this->m_name;
      }
      
      void Person::setName(const QString &name)
      {
          if (this->m_name != name) {
              this->m_name = name;
      
              emit this->nameChanged(name);
          }
      }
      
      // birthdayparty.h
      #ifndef BIRTHDAYPARTY_H
      #define BIRTHDAYPARTY_H
      
      #include <QObject>
      
      #include <QQmlListProperty>
      
      #include "person.h"
      
      class BirthdayParty : public QObject
      {
          Q_OBJECT
          Q_PROPERTY(Person* host READ host WRITE setHost)
          Q_PROPERTY(QQmlListProperty<Person> guests READ guests)
          Q_CLASSINFO("DefaultProperty", "guests")
      //    QML_ELEMENT
      public:
          BirthdayParty(QObject *parent = nullptr);
      
          Person* host() const;
          void setHost(Person *host);
      
          QQmlListProperty<Person> guests();
          int guestCount() const;
          Person* guest(int) const;
      
      private:
          Person *m_host;
          QList<Person*> m_guests;
      };
      
      #endif // BIRTHDAYPARTY_H
      
      // birthdayparty.cpp
      #include "birthdayparty.h"
      
      BirthdayParty::BirthdayParty(QObject *parent) : QObject(parent)
      {
      
      }
      
      Person* BirthdayParty::host() const
      {
          return this->m_host;
      }
      
      void BirthdayParty::setHost(Person *host)
      {
          this->m_host = host;
      }
      
      QQmlListProperty<Person> BirthdayParty::guests()
      {
          return QQmlListProperty<Person>(this, this->m_guests);
      }
      
      int BirthdayParty::guestCount() const
      {
          return this->m_guests.length();
      }
      
      Person* BirthdayParty::guest(int i) const
      {
          return this->m_guests[i];
      }
      
      // main.cpp
      #include <QGuiApplication>
      #include <QQmlApplicationEngine>
      
      #include "person.h"
      #include "birthdayparty.h"
      
      int main(int argc, char *argv[])
      {
          QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
      
          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);
      
          qmlRegisterType<Person>("ExtendingExample", 1, 0, "Person");
          qmlRegisterType<BirthdayParty>("ExtendingExample", 1, 0, "BirthdayParty");
      
          engine.load(url);
      
          return app.exec();
      }
      

      and using in QML

      // main.qml
      import QtQuick 2.12
      import QtQuick.Window 2.12
      
      import ExtendingExample 1.0
      
      Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
      
        BirthdayParty {
          host: Person {
            name: "John Doe"
          }
      
          Person {
            name: "Jane Doe"
          }
          Person {
            name: "Mary Smith"
          }
          Person {
            name: "Robert Brown"
          }
        }
      }
      

      This works except the warning in compile time.

      warning: ‘QQmlListProperty<T>::QQmlListProperty(QObject*, QList<T*>&) [with T = Person]’ is deprecated: Use constructor taking QList pointer, and gain improved performance [-Wdeprecated-declarations]
      

      so I replaced QQmlListProperty<Person> to QList<Person*>.

      Q_PROPERTY(QList<Person*> guests READ guests)
      ...
      QList<Person*> guests();
      ...
      QList<Person*> BirthdayParty::guests()
      {
          return this->m_guests;
      }
      

      This time, an error occured in QML.

      Invalid property assignment: "guests" is a read-only property
      

      again, I added WRITE method to the property.

      Q_PROPERTY(QList<Person*> guests WRITE setGuests READ guests)
                                       ^
      ...
      void BirthdayParty::setGuests(QList<Person*> guests)
      {
          this->m_guests = guests;
      }
      

      But QML error message is,

      Cannot assign to property of unknown type "QList<Person*>".
      

      How can I solve this? I don't want to see deprecated warnings because Qt 5.15 is the last Qt5 version so my project may won't work next Qt6 and very difficult to migrate to.

      J.Hilk 1 Reply Last reply Reply Quote 0
      • J.Hilk
        J.Hilk Moderators @Yujeonja last edited by

        @Yujeonja replace QList<Person*> with QList<QObject*> thats supported and on the qml side happens an "implicit cast" when you try to access Person functions

        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct

        Qt Needs YOUR vote: https://bugreports.qt.io/browse/QTQAINFRA-4121


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        1 Reply Last reply Reply Quote 0
        • GrecKo
          GrecKo Qt Champions 2018 last edited by

          The warning tells you exactly what to do.

          replace return QQmlListProperty<Person>(this, this->m_guests); with return QQmlListProperty<Person>(this, &this->m_guests);

          1 Reply Last reply Reply Quote 4
          • Y
            Yujeonja last edited by

            I misread the documents and warning. The deprecated is constructor not class. That constructor is removed from the QQmlListProperty documentation and replaced with new one and are very similar..

            1 Reply Last reply Reply Quote 2
            • First post
              Last post