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. Declare list<vector2d> in QML and pass it to a C++ function which appends to the list?
Forum Updated to NodeBB v4.3 + New Features

Declare list<vector2d> in QML and pass it to a C++ function which appends to the list?

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 2 Posters 299 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.
  • Tom assoT Offline
    Tom assoT Offline
    Tom asso
    wrote on last edited by Tom asso
    #1

    How to declare a QList<QVector2D> in QML, then pass as an argument to an INVOKABLE C++ function, which appends to the QList? Fails at run-time.

    C++ pseudocode:

    class TopoDataItem : public QObject {
      Q_OBJECT
      Q_INVOKABLE bool runTest(QList<QVector2D> *qprofile)
    }
    

    main.qml declares a list<vector2d> then passes that to the C++ when a button is pressed:

    // Declare bathymetry profile
    property list<vector2d> profile
    [...]
    Button {
      text: qsTr('run test')
      onPressed: {topoDataItem.runTest(profile)}   
    }
    

    The call to topoDataItem.runTest(profile) generates this error:

    "Could not convert argument 0 at"
    	 "expression for onPressed@qrc:/main.qml:174"
    qrc:/main.qml:174: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed.
    

    What am I doing wrong? How should TopoDataItem::runTest() be declared, and how should it be invoked from QML?
    Thanks!

    1 Reply Last reply
    0
    • jeremy_kJ jeremy_k

      @Tom-asso said in Declare list<vector2d> in QML and pass it to a C++ function which appends to the list?:

      @jeremy_k I change the function signature to:

      bool TopoDataItem::runTest(QList<QVector2D> &qProfile)
      

      Now when I invoke from QML I get this error:

      Error: Unknown method parameter type: QList<QVector2D>&
      

      The bridge between QML and C++ uses the metatype system.

      Background reading:
      https://doc.qt.io/qt-6/qmetatype.html#Q_DECLARE_METATYPE

      in particular:

      Some types are registered automatically and do not need this macro:

      Pointers to classes derived from QObject
      QList<T>, QQueue<T>, QStack<T> or QSet<T> where T is a registered meta type
      QHash<T1, T2>, QMap<T1, T2> or std::pair<T1, T2> where T1 and T2 are registered meta types
      QPointer<T>, QSharedPointer<T>, QWeakPointer<T>, where T is a class that derives from QObject
      Enumerations registered with Q_ENUM or Q_FLAG
      Classes that have a Q_GADGET macro
      

      Note that pointer and reference to QList of registered types is not in that list. I'm mildly surprised that a const reference works. QList is implicitly shared, making copy construction relatively cheap.

      If I make the function argument const like this:

      bool TopoDataItem::runTest(const QList<QVector2D> &qProfile)
      

      Now QML successfully calls the function - but I cannot append to the QList, since it is declared const. But runTest() needs to add content to the QList<QVector2D> profile argument. What am I missing here?
      Thanks!

      See above concerning the metatype system.

      Additionally, consider the ownership of objects in the list. The minimal non-working example in the first post suggests that the non-QObject objects are created by QML/javascript. Removing them from C++ can be a problem. For QObject instances, there's QJSEngine::setObjectOwnership(). For QVector2D, I have no idea.

      Tom assoT Offline
      Tom assoT Offline
      Tom asso
      wrote on last edited by
      #5

      @jeremy_k - thanks for that clarification.
      I ended up defining runTest() as follows:

      INVOKABLE QList<QVector2D> TopoDataItem::runTest(void ) {
        QList<QVector2D> profile;
        // Add content to profile
        [...]
        return profile;
      }
      

      The QML invokes the method as follows:

      Button {
        text: qsTr('run test')
        onPressed: {
          var profile = topoDataItem.runTest();
          // Do stuff with profile data
          [...]
        }   
      }
      

      This seems to work with my application, without need to register additional stuff with the metatype system.

      1 Reply Last reply
      0
      • jeremy_kJ Offline
        jeremy_kJ Offline
        jeremy_k
        wrote on last edited by
        #2

        Have you tried QList<QVector2D>, rather than a pointer to QList?

        #include <QGuiApplication>
        #include <QQmlApplicationEngine>
        
        int main(int argc, char *argv[])
        {
            QGuiApplication app(argc, argv);
            QQmlApplicationEngine engine;
        
            QObject::connect(
                &engine,
                &QQmlApplicationEngine::objectCreated,
                [&engine](QObject *obj, const QUrl & url) {
                    qDebug() << obj->property("s");
                });
        
            engine.loadData("import QtQuick; QtObject { property list<vector2d> s }");
        
            return app.exec();
        }
        

        Output with Qt 6.5:

        QVariant(QList<QVector2D>, QList())
        

        Asking a question about code? http://eel.is/iso-c++/testcase/

        Tom assoT 1 Reply Last reply
        1
        • jeremy_kJ jeremy_k

          Have you tried QList<QVector2D>, rather than a pointer to QList?

          #include <QGuiApplication>
          #include <QQmlApplicationEngine>
          
          int main(int argc, char *argv[])
          {
              QGuiApplication app(argc, argv);
              QQmlApplicationEngine engine;
          
              QObject::connect(
                  &engine,
                  &QQmlApplicationEngine::objectCreated,
                  [&engine](QObject *obj, const QUrl & url) {
                      qDebug() << obj->property("s");
                  });
          
              engine.loadData("import QtQuick; QtObject { property list<vector2d> s }");
          
              return app.exec();
          }
          

          Output with Qt 6.5:

          QVariant(QList<QVector2D>, QList())
          
          Tom assoT Offline
          Tom assoT Offline
          Tom asso
          wrote on last edited by Tom asso
          #3

          @jeremy_k I change the function signature to:

          bool TopoDataItem::runTest(QList<QVector2D> &qProfile)
          

          Now when I invoke from QML I get this error:

          Error: Unknown method parameter type: QList<QVector2D>&
          

          If I make the function argument const like this:

          bool TopoDataItem::runTest(const QList<QVector2D> &qProfile)
          

          Now QML successfully calls the function - but I cannot append to the QList, since it is declared const. But runTest() needs to add content to the QList<QVector2D> profile argument. What am I missing here?
          Thanks!

          jeremy_kJ 1 Reply Last reply
          0
          • Tom assoT Tom asso

            @jeremy_k I change the function signature to:

            bool TopoDataItem::runTest(QList<QVector2D> &qProfile)
            

            Now when I invoke from QML I get this error:

            Error: Unknown method parameter type: QList<QVector2D>&
            

            If I make the function argument const like this:

            bool TopoDataItem::runTest(const QList<QVector2D> &qProfile)
            

            Now QML successfully calls the function - but I cannot append to the QList, since it is declared const. But runTest() needs to add content to the QList<QVector2D> profile argument. What am I missing here?
            Thanks!

            jeremy_kJ Offline
            jeremy_kJ Offline
            jeremy_k
            wrote on last edited by
            #4

            @Tom-asso said in Declare list<vector2d> in QML and pass it to a C++ function which appends to the list?:

            @jeremy_k I change the function signature to:

            bool TopoDataItem::runTest(QList<QVector2D> &qProfile)
            

            Now when I invoke from QML I get this error:

            Error: Unknown method parameter type: QList<QVector2D>&
            

            The bridge between QML and C++ uses the metatype system.

            Background reading:
            https://doc.qt.io/qt-6/qmetatype.html#Q_DECLARE_METATYPE

            in particular:

            Some types are registered automatically and do not need this macro:

            Pointers to classes derived from QObject
            QList<T>, QQueue<T>, QStack<T> or QSet<T> where T is a registered meta type
            QHash<T1, T2>, QMap<T1, T2> or std::pair<T1, T2> where T1 and T2 are registered meta types
            QPointer<T>, QSharedPointer<T>, QWeakPointer<T>, where T is a class that derives from QObject
            Enumerations registered with Q_ENUM or Q_FLAG
            Classes that have a Q_GADGET macro
            

            Note that pointer and reference to QList of registered types is not in that list. I'm mildly surprised that a const reference works. QList is implicitly shared, making copy construction relatively cheap.

            If I make the function argument const like this:

            bool TopoDataItem::runTest(const QList<QVector2D> &qProfile)
            

            Now QML successfully calls the function - but I cannot append to the QList, since it is declared const. But runTest() needs to add content to the QList<QVector2D> profile argument. What am I missing here?
            Thanks!

            See above concerning the metatype system.

            Additionally, consider the ownership of objects in the list. The minimal non-working example in the first post suggests that the non-QObject objects are created by QML/javascript. Removing them from C++ can be a problem. For QObject instances, there's QJSEngine::setObjectOwnership(). For QVector2D, I have no idea.

            Asking a question about code? http://eel.is/iso-c++/testcase/

            Tom assoT 1 Reply Last reply
            3
            • jeremy_kJ jeremy_k

              @Tom-asso said in Declare list<vector2d> in QML and pass it to a C++ function which appends to the list?:

              @jeremy_k I change the function signature to:

              bool TopoDataItem::runTest(QList<QVector2D> &qProfile)
              

              Now when I invoke from QML I get this error:

              Error: Unknown method parameter type: QList<QVector2D>&
              

              The bridge between QML and C++ uses the metatype system.

              Background reading:
              https://doc.qt.io/qt-6/qmetatype.html#Q_DECLARE_METATYPE

              in particular:

              Some types are registered automatically and do not need this macro:

              Pointers to classes derived from QObject
              QList<T>, QQueue<T>, QStack<T> or QSet<T> where T is a registered meta type
              QHash<T1, T2>, QMap<T1, T2> or std::pair<T1, T2> where T1 and T2 are registered meta types
              QPointer<T>, QSharedPointer<T>, QWeakPointer<T>, where T is a class that derives from QObject
              Enumerations registered with Q_ENUM or Q_FLAG
              Classes that have a Q_GADGET macro
              

              Note that pointer and reference to QList of registered types is not in that list. I'm mildly surprised that a const reference works. QList is implicitly shared, making copy construction relatively cheap.

              If I make the function argument const like this:

              bool TopoDataItem::runTest(const QList<QVector2D> &qProfile)
              

              Now QML successfully calls the function - but I cannot append to the QList, since it is declared const. But runTest() needs to add content to the QList<QVector2D> profile argument. What am I missing here?
              Thanks!

              See above concerning the metatype system.

              Additionally, consider the ownership of objects in the list. The minimal non-working example in the first post suggests that the non-QObject objects are created by QML/javascript. Removing them from C++ can be a problem. For QObject instances, there's QJSEngine::setObjectOwnership(). For QVector2D, I have no idea.

              Tom assoT Offline
              Tom assoT Offline
              Tom asso
              wrote on last edited by
              #5

              @jeremy_k - thanks for that clarification.
              I ended up defining runTest() as follows:

              INVOKABLE QList<QVector2D> TopoDataItem::runTest(void ) {
                QList<QVector2D> profile;
                // Add content to profile
                [...]
                return profile;
              }
              

              The QML invokes the method as follows:

              Button {
                text: qsTr('run test')
                onPressed: {
                  var profile = topoDataItem.runTest();
                  // Do stuff with profile data
                  [...]
                }   
              }
              

              This seems to work with my application, without need to register additional stuff with the metatype system.

              1 Reply Last reply
              0
              • Tom assoT Tom asso has marked this topic as solved on

              • Login

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