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. Access List of Objects in QML
Forum Update on Monday, May 27th 2025

Access List of Objects in QML

Scheduled Pinned Locked Moved Solved QML and Qt Quick
13 Posts 2 Posters 3.7k 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.
  • T Offline
    T Offline
    Throndar
    wrote on 10 Sept 2018, 13:34 last edited by Throndar 9 Oct 2018, 13:50
    #1

    Hello,

    I build a class for multiple clients in my program to store the connection data of the multiple clients responding, to show in QML (mostly QString, bool, int). Each Client should be stored in its own Object.

    When I receive a response from a Client I create a new client-Object with the Data provided and store it in a QMap<QString, *client> with the IP (QString) as Key. This works quite fine and from C++ an I am able to access the Data.

    Now I am stuck at the point of trying to access the collected data in the QMap in QML.

    In the client-Class all Properties are setup with QProperty:

    #ifndef MOVIECLIENT_H
    #define MOVIECLIENT_H
    
    #include <QObject>
    #include <QMetaType>
    #include <QMap>
    #include <QDebug>
    
    class MovieClient : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
        Q_PROPERTY(QString address READ address WRITE setAddress NOTIFY addressChanged)
        Q_PROPERTY(QString version READ version WRITE setVersion NOTIFY versionChanged)
        Q_PROPERTY(int port READ port WRITE setPort NOTIFY portChanged)
    
    public:
        explicit MovieClient(QObject *parent = nullptr);
        MovieClient(const QString &name, const QString &version, const QString &address, const int &port, QObject *parent = nullptr);
        MovieClient(const MovieClient &other);
        ~MovieClient();
    
        QString name() const;
        void setName(const QString &name);
    
        QString address() const;
        void setAddress(const QString &address);
    
        QString version() const;
        void setVersion(const QString &version);
    
        int port() const;
        void setPort(const int &port);
    
    signals:
        void nameChanged();
        void addressChanged();
        void portChanged();
    
    private:
        // Connection-Information
        QString m_name;
        QString m_address;
        QString m_version;
        int m_port;
    
    public slots:
    };
    
    Q_DECLARE_METATYPE(MovieClient)
    #endif // MOVIECLIENT_H
    

    In the Receiver Class the QMap containing the MovieClients is located and on Message received a new Client ist created an added to the QMap. There I also used Q_PROPERTY to make the QMap know:

    #ifndef UDPRECEIVER_H
    #define UDPRECEIVER_H
    
    #include <QObject>
    #include <QHostAddress>
    #include <QUdpSocket>
    #include <QtNetwork>
    #include <QVariant>
    #include <QVariantMap>
    #include <QJsonDocument>
    #include "movieclient.h"
    #include <QMap>
    
    typedef QMap<QString, MovieClient*> movies;
    
    class UdpReceiver : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(movies movieClientList MEMBER movieClients)
    
    public:
        explicit UdpReceiver(QObject *parent = nullptr);
        UdpReceiver(const UdpReceiver &receiver);
        ~UdpReceiver();
        Q_INVOKABLE void clearClientlist();
    
    
    signals:
        void dataReceived();
        void jsonClientListUpdated(QString jCList);
        void movieClientListCleared();
    
    private slots:
        void processPendingDatagrams();
    
    private:
        void createJSON();
        // QMap der Clients
        QMap<QString, MovieClient*> movieClients;
        QUdpSocket udpSocket4;
        QHostAddress groupAddress4;
    };
    
    Q_DECLARE_METATYPE(UdpReceiver)
    
    #endif // UDPRECEIVER_H
    

    in the Main.cpp i set the Context Property for the UdpReceiverClass to Access it from QML

    UdpReceiver uReceiver;
    qRegisterMetaType<MovieClient>("movieClient");
    qRegisterMetaType<movies>("movies");
    engine.rootContext()->setContextProperty("UdpReceiver", &uReceiver);
    

    and when I try to access now in QML the autocomplete goes up to:

    console.log(UdpReceiver.movieClientList)
    

    and there it stops, none of the geter/setter Methods are accessible.
    The console.log when i send this out states "QVariant(QMap<QString,MovieClients*>)" so at least it seem to know the structure but I don't get any real Data from within the QMap.

    Now I kinda wonder how I am able to access the Data or if my try to make the List of Clients is completely wrong. I hope someone can help me with my problem.

    And sorry for my bad English since it's not my native language, I hope you can understand my problem.

    Thanks in Advance

    D 1 Reply Last reply 10 Sept 2018, 16:32
    0
    • T Throndar
      10 Sept 2018, 13:34

      Hello,

      I build a class for multiple clients in my program to store the connection data of the multiple clients responding, to show in QML (mostly QString, bool, int). Each Client should be stored in its own Object.

      When I receive a response from a Client I create a new client-Object with the Data provided and store it in a QMap<QString, *client> with the IP (QString) as Key. This works quite fine and from C++ an I am able to access the Data.

      Now I am stuck at the point of trying to access the collected data in the QMap in QML.

      In the client-Class all Properties are setup with QProperty:

      #ifndef MOVIECLIENT_H
      #define MOVIECLIENT_H
      
      #include <QObject>
      #include <QMetaType>
      #include <QMap>
      #include <QDebug>
      
      class MovieClient : public QObject
      {
          Q_OBJECT
          Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
          Q_PROPERTY(QString address READ address WRITE setAddress NOTIFY addressChanged)
          Q_PROPERTY(QString version READ version WRITE setVersion NOTIFY versionChanged)
          Q_PROPERTY(int port READ port WRITE setPort NOTIFY portChanged)
      
      public:
          explicit MovieClient(QObject *parent = nullptr);
          MovieClient(const QString &name, const QString &version, const QString &address, const int &port, QObject *parent = nullptr);
          MovieClient(const MovieClient &other);
          ~MovieClient();
      
          QString name() const;
          void setName(const QString &name);
      
          QString address() const;
          void setAddress(const QString &address);
      
          QString version() const;
          void setVersion(const QString &version);
      
          int port() const;
          void setPort(const int &port);
      
      signals:
          void nameChanged();
          void addressChanged();
          void portChanged();
      
      private:
          // Connection-Information
          QString m_name;
          QString m_address;
          QString m_version;
          int m_port;
      
      public slots:
      };
      
      Q_DECLARE_METATYPE(MovieClient)
      #endif // MOVIECLIENT_H
      

      In the Receiver Class the QMap containing the MovieClients is located and on Message received a new Client ist created an added to the QMap. There I also used Q_PROPERTY to make the QMap know:

      #ifndef UDPRECEIVER_H
      #define UDPRECEIVER_H
      
      #include <QObject>
      #include <QHostAddress>
      #include <QUdpSocket>
      #include <QtNetwork>
      #include <QVariant>
      #include <QVariantMap>
      #include <QJsonDocument>
      #include "movieclient.h"
      #include <QMap>
      
      typedef QMap<QString, MovieClient*> movies;
      
      class UdpReceiver : public QObject
      {
          Q_OBJECT
          Q_PROPERTY(movies movieClientList MEMBER movieClients)
      
      public:
          explicit UdpReceiver(QObject *parent = nullptr);
          UdpReceiver(const UdpReceiver &receiver);
          ~UdpReceiver();
          Q_INVOKABLE void clearClientlist();
      
      
      signals:
          void dataReceived();
          void jsonClientListUpdated(QString jCList);
          void movieClientListCleared();
      
      private slots:
          void processPendingDatagrams();
      
      private:
          void createJSON();
          // QMap der Clients
          QMap<QString, MovieClient*> movieClients;
          QUdpSocket udpSocket4;
          QHostAddress groupAddress4;
      };
      
      Q_DECLARE_METATYPE(UdpReceiver)
      
      #endif // UDPRECEIVER_H
      

      in the Main.cpp i set the Context Property for the UdpReceiverClass to Access it from QML

      UdpReceiver uReceiver;
      qRegisterMetaType<MovieClient>("movieClient");
      qRegisterMetaType<movies>("movies");
      engine.rootContext()->setContextProperty("UdpReceiver", &uReceiver);
      

      and when I try to access now in QML the autocomplete goes up to:

      console.log(UdpReceiver.movieClientList)
      

      and there it stops, none of the geter/setter Methods are accessible.
      The console.log when i send this out states "QVariant(QMap<QString,MovieClients*>)" so at least it seem to know the structure but I don't get any real Data from within the QMap.

      Now I kinda wonder how I am able to access the Data or if my try to make the List of Clients is completely wrong. I hope someone can help me with my problem.

      And sorry for my bad English since it's not my native language, I hope you can understand my problem.

      Thanks in Advance

      D Offline
      D Offline
      Diracsbracket
      wrote on 10 Sept 2018, 16:32 last edited by Diracsbracket 9 Oct 2018, 16:49
      #2

      @Throndar
      To pass your QMap, define it as a QVariantMap instead (which is just a typedef for QMap<QString, QVariant>
      http://doc.qt.io/qt-5/qvariant.html#QVariantMap-typedef

      Then, there is an automatic conversion for it when passed to QML' JavaScript context.
      http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#qvariantlist-and-qvariantmap-to-javascript-array-and-object

      So, you can get rid of your custom typedef altogether

      typedef QMap<QString, MovieClient*> movies; //<-- NO LONGER NEEDED
      qRegisterMetaType<movies>("movies"); //<-- NOT NEEDED
      

      and define movieClients as

       QVariantMap movieClients;
      

      and

       Q_PROPERTY(QVariantMap movieClientList MEMBER movieClients)
      

      You must then fill your map as e.g.:

      movieClients.insert("124.244.23.22", QVariant::fromValue(new MovieClient("client1", "v1", "124.244.23.22", 22, this)));
      

      (the important part above is the conversion to QVariant).

      Now, you can access the data in JavaScript as:

              var anObject = udpReceiver.movieClientList
      
              console.debug(Object.keys(anObject).length)
      
              for (var prop in anObject) {
                  var client = anObject[prop]
                  console.debug(client.name + " " + client.address + " " + client.port + " " + client.version)
              }
      

      Good luck.

      T 1 Reply Last reply 11 Sept 2018, 08:39
      3
      • D Diracsbracket
        10 Sept 2018, 16:32

        @Throndar
        To pass your QMap, define it as a QVariantMap instead (which is just a typedef for QMap<QString, QVariant>
        http://doc.qt.io/qt-5/qvariant.html#QVariantMap-typedef

        Then, there is an automatic conversion for it when passed to QML' JavaScript context.
        http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#qvariantlist-and-qvariantmap-to-javascript-array-and-object

        So, you can get rid of your custom typedef altogether

        typedef QMap<QString, MovieClient*> movies; //<-- NO LONGER NEEDED
        qRegisterMetaType<movies>("movies"); //<-- NOT NEEDED
        

        and define movieClients as

         QVariantMap movieClients;
        

        and

         Q_PROPERTY(QVariantMap movieClientList MEMBER movieClients)
        

        You must then fill your map as e.g.:

        movieClients.insert("124.244.23.22", QVariant::fromValue(new MovieClient("client1", "v1", "124.244.23.22", 22, this)));
        

        (the important part above is the conversion to QVariant).

        Now, you can access the data in JavaScript as:

                var anObject = udpReceiver.movieClientList
        
                console.debug(Object.keys(anObject).length)
        
                for (var prop in anObject) {
                    var client = anObject[prop]
                    console.debug(client.name + " " + client.address + " " + client.port + " " + client.version)
                }
        

        Good luck.

        T Offline
        T Offline
        Throndar
        wrote on 11 Sept 2018, 08:39 last edited by
        #3

        Hello @Diracsbracket ,

        at first, I want to thank you very very much for your help. In QML I can reach the Variant List and this is really awesome :)

        But now I have three smaller new problems:

        1. I create a JSON Document of all the Clients I received to fill a Tableview to be able to choose one from a List. This function also emitted a SIGNAL every time a new entry in the JSON was made.
          With QMap I did this with a for-loop:
        QJsonArray jClients;
        QString jCList;
        
        for(auto client : movieClients.toStdMap())
                    {
                        QJsonObject cEntry;
                        cEntry.insert("name", QJsonValue::fromVariant(client.second->name()));
                        cEntry.insert("ipaddress", QJsonValue::fromVariant(client.second->address()));
                        cEntry.insert("version", QJsonValue::fromVariant(client.second->version()));
                        cEntry.insert("port", QJsonValue::fromVariant(client.second->port()));
                        jClients.push_front(cEntry);
                    }
            jCList = QJsonDocument(jClients).toJson();
            emit jsonClientListUpdated(jCList);
        

        It seems that I can't access the Properties this way. Is there a way to access the Values without the need of the key in the loop? (all the Answers I found online refered to QVariantMap["key"] but the key is set by the client responsing to a call, so i don't have that in the loop)

        1. When i start a new search, I have to clear the List of the exisiting Clients to make sure no Client is allready exisiting. I did this prior with
        qDeleteAll(movieClients);
        movieClients.clear();
        

        The QDeleteAll seems not to work with the QVariantMap since its no Pointer if I understood the Documentation correctly. Is there a safe way to clear out all the Items stored in the QVariantMap and Clear the QVariantMap itself?

        1. If i want to change some Values in the Objects with the UI, I tried to Change the Properties with the WRITE Q_Property specified in the Class of MovieClient
        console.debug(client.name + " " + client.address + " " + client.port + " " + client.version)
        client.setName("ClientsNewName")
        console.debug(client.name + " " + client.address + " " + client.port + " " + client.version)
        

        But this doesn't work this way. Is there a way to Change the Values of the Propertys after writing them to the QVariantMap or did I just forget something to Access them?

        At the Moment I'm still wondering if it would be a good Idea to make a QVariantMap to show the Stats on the UI with QML and keep the old QMap for C++ to be able to call the set-Function to change Properties. But keeping two complete Sets of identical Data seems kinda a waste of resources.

        Thanks in advance

        D 1 Reply Last reply 11 Sept 2018, 08:55
        0
        • T Throndar
          11 Sept 2018, 08:39

          Hello @Diracsbracket ,

          at first, I want to thank you very very much for your help. In QML I can reach the Variant List and this is really awesome :)

          But now I have three smaller new problems:

          1. I create a JSON Document of all the Clients I received to fill a Tableview to be able to choose one from a List. This function also emitted a SIGNAL every time a new entry in the JSON was made.
            With QMap I did this with a for-loop:
          QJsonArray jClients;
          QString jCList;
          
          for(auto client : movieClients.toStdMap())
                      {
                          QJsonObject cEntry;
                          cEntry.insert("name", QJsonValue::fromVariant(client.second->name()));
                          cEntry.insert("ipaddress", QJsonValue::fromVariant(client.second->address()));
                          cEntry.insert("version", QJsonValue::fromVariant(client.second->version()));
                          cEntry.insert("port", QJsonValue::fromVariant(client.second->port()));
                          jClients.push_front(cEntry);
                      }
              jCList = QJsonDocument(jClients).toJson();
              emit jsonClientListUpdated(jCList);
          

          It seems that I can't access the Properties this way. Is there a way to access the Values without the need of the key in the loop? (all the Answers I found online refered to QVariantMap["key"] but the key is set by the client responsing to a call, so i don't have that in the loop)

          1. When i start a new search, I have to clear the List of the exisiting Clients to make sure no Client is allready exisiting. I did this prior with
          qDeleteAll(movieClients);
          movieClients.clear();
          

          The QDeleteAll seems not to work with the QVariantMap since its no Pointer if I understood the Documentation correctly. Is there a safe way to clear out all the Items stored in the QVariantMap and Clear the QVariantMap itself?

          1. If i want to change some Values in the Objects with the UI, I tried to Change the Properties with the WRITE Q_Property specified in the Class of MovieClient
          console.debug(client.name + " " + client.address + " " + client.port + " " + client.version)
          client.setName("ClientsNewName")
          console.debug(client.name + " " + client.address + " " + client.port + " " + client.version)
          

          But this doesn't work this way. Is there a way to Change the Values of the Propertys after writing them to the QVariantMap or did I just forget something to Access them?

          At the Moment I'm still wondering if it would be a good Idea to make a QVariantMap to show the Stats on the UI with QML and keep the old QMap for C++ to be able to call the set-Function to change Properties. But keeping two complete Sets of identical Data seems kinda a waste of resources.

          Thanks in advance

          D Offline
          D Offline
          Diracsbracket
          wrote on 11 Sept 2018, 08:55 last edited by Diracsbracket 9 Nov 2018, 08:56
          #4

          @Throndar said in Access List of Objects in QML:

          At the Moment I'm still wondering if it would be a good Idea to make a QVariantMap to show the Stats on the UI with QML and keep the old QMap for C++

          I think you should consider storing your data in a model instead. This will make everything much simpler, including the interfacing between C++/QML and solve all of the problems you are currently facing.

          Have a look at:
          http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel-subclass

          T 1 Reply Last reply 11 Sept 2018, 12:48
          2
          • D Diracsbracket
            11 Sept 2018, 08:55

            @Throndar said in Access List of Objects in QML:

            At the Moment I'm still wondering if it would be a good Idea to make a QVariantMap to show the Stats on the UI with QML and keep the old QMap for C++

            I think you should consider storing your data in a model instead. This will make everything much simpler, including the interfacing between C++/QML and solve all of the problems you are currently facing.

            Have a look at:
            http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel-subclass

            T Offline
            T Offline
            Throndar
            wrote on 11 Sept 2018, 12:48 last edited by Throndar 9 Nov 2018, 14:38
            #5

            Hello @Diracsbracket

            thank you very much again for your help.

            I just tried the last four hours to adept the animal example on the Link you provided to create a ClientModel but I still can't get it working in my Program.

            I already tried the Youtube Tutorial Linked on the Documentation on Model in QML
            https://www.youtube.com/watch?v=9BcAYDlpuT8&feature=youtu.be
            this worked well but seemed to be used to populate a ListView (the only thing that I got to work on my Project without bigger problems with QJson)

            I also tried to work through the QT Documentation on http://doc.qt.io/qt-5/qabstractitemmodel.html but this got me even more confused since it States of a Model-index with rows and columns when I only try to build sets of simple Datatypes.

            Perhaps somebody has some additional source of information / or an Example on how to create a model for data to be used in QML Context? Everything I found so far referred to a ListView instead of a List of Objects

            I'm kinda wondering how hard it is to get a simple thing like a List of Objects with multiple Properties accessible in QML and would really appreciate additional Information to get me started.

            If there is a better / easier Way to store Information about (multiple) Clients (each containing multiple QString, bool, int) in a Struct / Vector or some other way, I am open for all suggestions. The only requirement is to read and write the properties and be able to access them in QML.

            Thanks in advance

            D 1 Reply Last reply 12 Sept 2018, 03:47
            0
            • T Throndar
              11 Sept 2018, 12:48

              Hello @Diracsbracket

              thank you very much again for your help.

              I just tried the last four hours to adept the animal example on the Link you provided to create a ClientModel but I still can't get it working in my Program.

              I already tried the Youtube Tutorial Linked on the Documentation on Model in QML
              https://www.youtube.com/watch?v=9BcAYDlpuT8&feature=youtu.be
              this worked well but seemed to be used to populate a ListView (the only thing that I got to work on my Project without bigger problems with QJson)

              I also tried to work through the QT Documentation on http://doc.qt.io/qt-5/qabstractitemmodel.html but this got me even more confused since it States of a Model-index with rows and columns when I only try to build sets of simple Datatypes.

              Perhaps somebody has some additional source of information / or an Example on how to create a model for data to be used in QML Context? Everything I found so far referred to a ListView instead of a List of Objects

              I'm kinda wondering how hard it is to get a simple thing like a List of Objects with multiple Properties accessible in QML and would really appreciate additional Information to get me started.

              If there is a better / easier Way to store Information about (multiple) Clients (each containing multiple QString, bool, int) in a Struct / Vector or some other way, I am open for all suggestions. The only requirement is to read and write the properties and be able to access them in QML.

              Thanks in advance

              D Offline
              D Offline
              Diracsbracket
              wrote on 12 Sept 2018, 03:47 last edited by
              #6

              @Throndar said in Access List of Objects in QML:

              I still can't get it working in my Program.

              Can you show us what you tried?
              Post your basic test code (C++, QML and main.cpp) using dummy (i.e. hard-coded) DB data. That's the only way to see what's missing.

              T 1 Reply Last reply 12 Sept 2018, 07:32
              1
              • D Diracsbracket
                12 Sept 2018, 03:47

                @Throndar said in Access List of Objects in QML:

                I still can't get it working in my Program.

                Can you show us what you tried?
                Post your basic test code (C++, QML and main.cpp) using dummy (i.e. hard-coded) DB data. That's the only way to see what's missing.

                T Offline
                T Offline
                Throndar
                wrote on 12 Sept 2018, 07:32 last edited by Throndar 9 Dec 2018, 07:43
                #7

                Hello @Diracsbracket,

                thanks again for your help. This is the Code for the first four Properties (if everything works each Client should get about 10-20 Properties).

                At the Point of the Code below the manually added Clients are stored in the Model and the Listview shows them (the List is quite ugly, but all the Values are there).

                The most important things that don't work are:
                Since the MovieClientModel is defined in the main.cpp I have found no way to create MovieClients in my "ReceiverClass" and store them in the Model created in main.cpp (the Receiver gets the Response from the Clients and Creates a Client with the Data received) this Created Client have to be added to the model.

                The ListView shows the Data of the manual created Clients, but I still struggle to get Information back from the Model like "if there is a Client 3, show me all his Properties". I found no way to search the model for data contained in it.

                The next important thing and I think it is connected to the one above, I have no idea how to access QProperies in MovieClient Objects or the Functions to set Properties (to Change the Name for Example).

                And since the Listview is not Clickable I tried to use the Model in a TableView who showed all the Items quite nicely.
                With the "onClicked" event if try to get the Information there I could console.log the row but again, no further data. I used the same method that worked on the List generated with JSON:

                onClicked: {
                                console.log(row) // >> working, shows index
                                console.log("Name: " + view2.model.get(row).name) // >> not working
                }
                

                The Model and Model implementation i currently use:

                the MovieClientModel:

                #ifndef MOVIECLIENTMODEL_H
                #define MOVIECLIENTMODEL_H
                
                #include <QAbstractListModel>
                #include "movieclient.h"
                
                class MovieClientModel : public QAbstractListModel
                {
                    Q_OBJECT
                public:
                    enum MovieClientRoles {
                        NameRole = Qt::UserRole,
                        AddressRole = Qt::UserRole + 1,
                        VersionRole = Qt::UserRole + 2,
                        PortRole = Qt::UserRole + 3
                    };
                
                    MovieClientModel(QObject *parent = nullptr);
                
                    void addMovieClient(const MovieClient &movieClient);
                    int rowCount(const QModelIndex &parent = QModelIndex()) const;
                    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
                
                protected:
                    QHash<int, QByteArray> roleNames() const;
                private:
                    QList<MovieClient> m_movieClients;
                };
                
                #endif // MOVIECLIENTMODEL_H
                

                the MovieClientModel.cpp

                #include "movieclientmodel.h"
                
                MovieClientModel::MovieClientModel(QObject *parent)
                    : QAbstractListModel (parent)
                {
                
                }
                
                void MovieClientModel::addMovieClient(const MovieClient &movieClient)
                {
                    beginInsertRows(QModelIndex(), rowCount(), rowCount());
                    m_movieClients << movieClient;
                    endInsertRows();
                }
                
                int MovieClientModel::rowCount(const QModelIndex &parent) const
                {
                    Q_UNUSED(parent);
                    return m_movieClients.count();
                }
                
                QVariant MovieClientModel::data(const QModelIndex &index, int role) const
                {
                    if (index.row() < 0 || index.row() >= m_movieClients.count())
                        return QVariant();
                
                    const MovieClient &movieClient = m_movieClients[index.row()];
                    if(role == NameRole)
                        return movieClient.name();
                    else if(role == AddressRole)
                        return movieClient.address();
                    else if(role == VersionRole)
                        return movieClient.version();
                    else if(role == PortRole)
                        return movieClient.version();
                
                }
                
                QHash<int, QByteArray> MovieClientModel::roleNames() const
                {
                    QHash<int, QByteArray> roles;
                    roles[NameRole] = "name";
                    roles[AddressRole] = "address";
                    roles[VersionRole] = "version";
                    roles[PortRole] = "port";
                    return roles;
                }
                

                in the Main.cpp:

                
                    MovieClientModel model;
                    model.addMovieClient(MovieClient("Client 1", "Version 1.2", "192.168.100.94", 2000));
                    model.addMovieClient(MovieClient("Client 2", "Version 1.2", "192.168.100.98", 5000));
                    model.addMovieClient(MovieClient("Client 3", "Version 1.2", "192.168.100.24", 1000));
                
                    engine.rootContext()->setContextProperty("MovieClientModel", &model);
                

                and in QML:

                
                        Button {
                            id: modelbutton
                            anchors.centerIn: parent
                            text: "modelTest"
                            onClicked: {
                                console.log(MovieClientModel.data(0, NameRole)) // >> not working, tried to Access data from the Model)
                            }
                        }
                
                        ListView {
                            id: movieClientModelList
                            width: 200; height: 250
                            
                            model: MovieClientModel
                            delegate: Text { text: "MovieClient: " + name + ", " + version + ", " + address + ", "  + port }            
                        }
                
                D 1 Reply Last reply 12 Sept 2018, 08:39
                0
                • T Throndar
                  12 Sept 2018, 07:32

                  Hello @Diracsbracket,

                  thanks again for your help. This is the Code for the first four Properties (if everything works each Client should get about 10-20 Properties).

                  At the Point of the Code below the manually added Clients are stored in the Model and the Listview shows them (the List is quite ugly, but all the Values are there).

                  The most important things that don't work are:
                  Since the MovieClientModel is defined in the main.cpp I have found no way to create MovieClients in my "ReceiverClass" and store them in the Model created in main.cpp (the Receiver gets the Response from the Clients and Creates a Client with the Data received) this Created Client have to be added to the model.

                  The ListView shows the Data of the manual created Clients, but I still struggle to get Information back from the Model like "if there is a Client 3, show me all his Properties". I found no way to search the model for data contained in it.

                  The next important thing and I think it is connected to the one above, I have no idea how to access QProperies in MovieClient Objects or the Functions to set Properties (to Change the Name for Example).

                  And since the Listview is not Clickable I tried to use the Model in a TableView who showed all the Items quite nicely.
                  With the "onClicked" event if try to get the Information there I could console.log the row but again, no further data. I used the same method that worked on the List generated with JSON:

                  onClicked: {
                                  console.log(row) // >> working, shows index
                                  console.log("Name: " + view2.model.get(row).name) // >> not working
                  }
                  

                  The Model and Model implementation i currently use:

                  the MovieClientModel:

                  #ifndef MOVIECLIENTMODEL_H
                  #define MOVIECLIENTMODEL_H
                  
                  #include <QAbstractListModel>
                  #include "movieclient.h"
                  
                  class MovieClientModel : public QAbstractListModel
                  {
                      Q_OBJECT
                  public:
                      enum MovieClientRoles {
                          NameRole = Qt::UserRole,
                          AddressRole = Qt::UserRole + 1,
                          VersionRole = Qt::UserRole + 2,
                          PortRole = Qt::UserRole + 3
                      };
                  
                      MovieClientModel(QObject *parent = nullptr);
                  
                      void addMovieClient(const MovieClient &movieClient);
                      int rowCount(const QModelIndex &parent = QModelIndex()) const;
                      QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
                  
                  protected:
                      QHash<int, QByteArray> roleNames() const;
                  private:
                      QList<MovieClient> m_movieClients;
                  };
                  
                  #endif // MOVIECLIENTMODEL_H
                  

                  the MovieClientModel.cpp

                  #include "movieclientmodel.h"
                  
                  MovieClientModel::MovieClientModel(QObject *parent)
                      : QAbstractListModel (parent)
                  {
                  
                  }
                  
                  void MovieClientModel::addMovieClient(const MovieClient &movieClient)
                  {
                      beginInsertRows(QModelIndex(), rowCount(), rowCount());
                      m_movieClients << movieClient;
                      endInsertRows();
                  }
                  
                  int MovieClientModel::rowCount(const QModelIndex &parent) const
                  {
                      Q_UNUSED(parent);
                      return m_movieClients.count();
                  }
                  
                  QVariant MovieClientModel::data(const QModelIndex &index, int role) const
                  {
                      if (index.row() < 0 || index.row() >= m_movieClients.count())
                          return QVariant();
                  
                      const MovieClient &movieClient = m_movieClients[index.row()];
                      if(role == NameRole)
                          return movieClient.name();
                      else if(role == AddressRole)
                          return movieClient.address();
                      else if(role == VersionRole)
                          return movieClient.version();
                      else if(role == PortRole)
                          return movieClient.version();
                  
                  }
                  
                  QHash<int, QByteArray> MovieClientModel::roleNames() const
                  {
                      QHash<int, QByteArray> roles;
                      roles[NameRole] = "name";
                      roles[AddressRole] = "address";
                      roles[VersionRole] = "version";
                      roles[PortRole] = "port";
                      return roles;
                  }
                  

                  in the Main.cpp:

                  
                      MovieClientModel model;
                      model.addMovieClient(MovieClient("Client 1", "Version 1.2", "192.168.100.94", 2000));
                      model.addMovieClient(MovieClient("Client 2", "Version 1.2", "192.168.100.98", 5000));
                      model.addMovieClient(MovieClient("Client 3", "Version 1.2", "192.168.100.24", 1000));
                  
                      engine.rootContext()->setContextProperty("MovieClientModel", &model);
                  

                  and in QML:

                  
                          Button {
                              id: modelbutton
                              anchors.centerIn: parent
                              text: "modelTest"
                              onClicked: {
                                  console.log(MovieClientModel.data(0, NameRole)) // >> not working, tried to Access data from the Model)
                              }
                          }
                  
                          ListView {
                              id: movieClientModelList
                              width: 200; height: 250
                              
                              model: MovieClientModel
                              delegate: Text { text: "MovieClient: " + name + ", " + version + ", " + address + ", "  + port }            
                          }
                  
                  D Offline
                  D Offline
                  Diracsbracket
                  wrote on 12 Sept 2018, 08:39 last edited by Diracsbracket 9 Dec 2018, 09:13
                  #8

                  @Throndar said in Access List of Objects in QML:

                  console.log(MovieClientModel.data(0, NameRole))

                  You are not using the correct arguments for the data() function.

                  QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
                  

                  0 is not a QModelIndex object. You can get the ModelIndex via the index(row, col, parent) property, e.g.

                  movieClientModel.index(0,0)
                  

                  (Note that I renamed the instance by making it start with a lowercase char; the type name has uppercase first char.)

                  The C++ enum item NameRole is not directly accessible in QML: You must register it using the Q_ENUM macro, but this requires you to register the MoveClientModel type too.
                  http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#enumeration-types

                  When you do all the above, you can access the data as:

                  console.log(movieClientModel.data(movieClientModel.index(0,0), MovieClientModel.NameRole))
                  

                  To avoid the hassle of the above syntax, I find it convenient to do this instead:
                  Add the following function to your model

                  Q_INVOKABLE QVariantMap get(int row);
                  

                  and implement is as follows:

                  QVariantMap MovieClientModel::get(int row)
                  {
                      QVariantMap res;
                      QModelIndex idx = index(row, 0);
                  
                      res["name"] = idx.data(NameRole);
                      res["address"] = idx.data(AddressRole);
                      res["version"] = idx.data(VersionRole);
                      res["port"] = idx.data(PortRole);
                  
                      return res;
                  }
                  

                  The above will get you the complete model row, with fields now easily accessible via their names, so in QML you can now do:

                  console.log(movieClientModel.get(0).address)
                  

                  Good luck!

                  T 1 Reply Last reply 12 Sept 2018, 09:49
                  2
                  • D Diracsbracket
                    12 Sept 2018, 08:39

                    @Throndar said in Access List of Objects in QML:

                    console.log(MovieClientModel.data(0, NameRole))

                    You are not using the correct arguments for the data() function.

                    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
                    

                    0 is not a QModelIndex object. You can get the ModelIndex via the index(row, col, parent) property, e.g.

                    movieClientModel.index(0,0)
                    

                    (Note that I renamed the instance by making it start with a lowercase char; the type name has uppercase first char.)

                    The C++ enum item NameRole is not directly accessible in QML: You must register it using the Q_ENUM macro, but this requires you to register the MoveClientModel type too.
                    http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#enumeration-types

                    When you do all the above, you can access the data as:

                    console.log(movieClientModel.data(movieClientModel.index(0,0), MovieClientModel.NameRole))
                    

                    To avoid the hassle of the above syntax, I find it convenient to do this instead:
                    Add the following function to your model

                    Q_INVOKABLE QVariantMap get(int row);
                    

                    and implement is as follows:

                    QVariantMap MovieClientModel::get(int row)
                    {
                        QVariantMap res;
                        QModelIndex idx = index(row, 0);
                    
                        res["name"] = idx.data(NameRole);
                        res["address"] = idx.data(AddressRole);
                        res["version"] = idx.data(VersionRole);
                        res["port"] = idx.data(PortRole);
                    
                        return res;
                    }
                    

                    The above will get you the complete model row, with fields now easily accessible via their names, so in QML you can now do:

                    console.log(movieClientModel.get(0).address)
                    

                    Good luck!

                    T Offline
                    T Offline
                    Throndar
                    wrote on 12 Sept 2018, 09:49 last edited by Throndar 9 Dec 2018, 09:50
                    #9

                    Hello @Diracsbracket,

                    wow, I thank you so very much for your help.
                    With the new Function to get the Object of the Index, I can access all the Data from the Entry and start filling my QML the for displaying the Properties.

                    I only have two question if you could help me again.

                    Is there a way to create MovieClients an add them to the MovieClientModel located in main from my Receiver class?

                    With the Test-MovieClients in the Main hardcoded build everything works fine, but since the answer from the Clients comes via TCP I let my Receiver-Class do the dynamic MovieClient-Creation till now.
                    In the Moment my Receiver-Class checks if there arrives Data on a specific address&port, parses it and if the message fits the expected message-definition from a Client it creates a client-object with the parameters received. Now I wonder how I can pass this MovieClient to the MovieClientModel on Creation.

                    The other Question states the changing of a MovieClient.
                    I think this could be done with a set-method similar to the get you provided to me. Or do you think it's better to delete the existing entry and create a new client with the new properties?

                    D 1 Reply Last reply 12 Sept 2018, 10:55
                    0
                    • T Throndar
                      12 Sept 2018, 09:49

                      Hello @Diracsbracket,

                      wow, I thank you so very much for your help.
                      With the new Function to get the Object of the Index, I can access all the Data from the Entry and start filling my QML the for displaying the Properties.

                      I only have two question if you could help me again.

                      Is there a way to create MovieClients an add them to the MovieClientModel located in main from my Receiver class?

                      With the Test-MovieClients in the Main hardcoded build everything works fine, but since the answer from the Clients comes via TCP I let my Receiver-Class do the dynamic MovieClient-Creation till now.
                      In the Moment my Receiver-Class checks if there arrives Data on a specific address&port, parses it and if the message fits the expected message-definition from a Client it creates a client-object with the parameters received. Now I wonder how I can pass this MovieClient to the MovieClientModel on Creation.

                      The other Question states the changing of a MovieClient.
                      I think this could be done with a set-method similar to the get you provided to me. Or do you think it's better to delete the existing entry and create a new client with the new properties?

                      D Offline
                      D Offline
                      Diracsbracket
                      wrote on 12 Sept 2018, 10:55 last edited by
                      #10

                      @Throndar said in Access List of Objects in QML:

                      Is there a way to create MovieClients an add them to the MovieClientModel located in main from my Receiver class?

                      Providing your Receiver object a reference to your model seems to be a straight-forward approach, no? Then you can invoke addMovieClient() from there.

                      Or do you think it's better to delete the existing entry and create a new client with the new properties?

                      That's completely up to you, but my first approach would be to edit the model entry for a given client rather than to delete and recreate it.

                      T 1 Reply Last reply 12 Sept 2018, 12:34
                      2
                      • D Diracsbracket
                        12 Sept 2018, 10:55

                        @Throndar said in Access List of Objects in QML:

                        Is there a way to create MovieClients an add them to the MovieClientModel located in main from my Receiver class?

                        Providing your Receiver object a reference to your model seems to be a straight-forward approach, no? Then you can invoke addMovieClient() from there.

                        Or do you think it's better to delete the existing entry and create a new client with the new properties?

                        That's completely up to you, but my first approach would be to edit the model entry for a given client rather than to delete and recreate it.

                        T Offline
                        T Offline
                        Throndar
                        wrote on 12 Sept 2018, 12:34 last edited by Throndar 9 Dec 2018, 12:35
                        #11

                        @Diracsbracket said in Access List of Objects in QML:

                        Providing your Receiver object a reference to your model seems to be a straight-forward approach, no? Then you can invoke addMovieClient() from there.

                        You are completely right (as always) and i really appreciate your help. At this spot, I am missing something. So far I used References for Function calls to let them work with the original Values. So I get what you intend to do.

                        Just like:

                        void myFunction(int &value){
                                value = 10;
                        }
                        

                        At first I tried to pass a reference to the MovieClientModel on the creation and changed to constructor on my Receiver, this resulted in all connect Statements to state "no matching function to call to connect".

                        The next attempt was to set a "setModel(&ClientModelView)" Function, this resulted in the Error that MovieClientsModel in the Receiver cannot be assigned with "=" to the passed Value.

                        Now I am completely unsure if I am at the right spot at all or if the passing of the Reference for Objects created in main.cpp is different from normal Functioncalls with a reference passed over.

                        D 1 Reply Last reply 12 Sept 2018, 13:20
                        0
                        • T Throndar
                          12 Sept 2018, 12:34

                          @Diracsbracket said in Access List of Objects in QML:

                          Providing your Receiver object a reference to your model seems to be a straight-forward approach, no? Then you can invoke addMovieClient() from there.

                          You are completely right (as always) and i really appreciate your help. At this spot, I am missing something. So far I used References for Function calls to let them work with the original Values. So I get what you intend to do.

                          Just like:

                          void myFunction(int &value){
                                  value = 10;
                          }
                          

                          At first I tried to pass a reference to the MovieClientModel on the creation and changed to constructor on my Receiver, this resulted in all connect Statements to state "no matching function to call to connect".

                          The next attempt was to set a "setModel(&ClientModelView)" Function, this resulted in the Error that MovieClientsModel in the Receiver cannot be assigned with "=" to the passed Value.

                          Now I am completely unsure if I am at the right spot at all or if the passing of the Reference for Objects created in main.cpp is different from normal Functioncalls with a reference passed over.

                          D Offline
                          D Offline
                          Diracsbracket
                          wrote on 12 Sept 2018, 13:20 last edited by Diracsbracket 9 Dec 2018, 13:20
                          #12

                          @Throndar
                          This thread is starting to look like a tutorial in programming...
                          I think you should review your C++ basics, as you now really have all the info you need to accomplish what you need.

                          T 1 Reply Last reply 12 Sept 2018, 14:41
                          1
                          • D Diracsbracket
                            12 Sept 2018, 13:20

                            @Throndar
                            This thread is starting to look like a tutorial in programming...
                            I think you should review your C++ basics, as you now really have all the info you need to accomplish what you need.

                            T Offline
                            T Offline
                            Throndar
                            wrote on 12 Sept 2018, 14:41 last edited by Throndar 9 Dec 2018, 14:54
                            #13

                            Hello @Diracsbracket

                            if think you are right again.

                            I never needed to pass References to own Classes or Models till now. So used the usual call of:

                            UdpReceiver uReceiver(&model);
                            
                            with the Constructor of
                            UdpReceiver(const MovieClientModel &model, QObject *parent = nullptr);
                            

                            after checking the Code again it seemed the Reason for the Errors where the CopyConstructor and Q_DECLARE_METATYPE Macro I used, trying to get the original QMap working in QML.

                            After removing these two the Call with the Reference to the MovieClientModel seem ok, now just the initialization of with the Reference make some problems.

                            Once again I thank you for your help and the Problems showed me that I need to clean up all the Stuff after trying something that didn't work and with the new AbstractModel I created with your tips i got huge step further.

                            1 Reply Last reply
                            0

                            8/13

                            12 Sept 2018, 08:39

                            • Login

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