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. Send data from C++ to QML model
Forum Updated to NodeBB v4.3 + New Features

Send data from C++ to QML model

Scheduled Pinned Locked Moved Solved QML and Qt Quick
6 Posts 3 Posters 7.1k Views 3 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.
  • XequtorX Offline
    XequtorX Offline
    Xequtor
    wrote on last edited by
    #1

    Hello All,

    Probably this has been discussed thousands of times and there are many posts about it, but I couldn't find any complete and useful one. I have a Qt Application with C++. My GUI is defined using multiple .qml files. Now I want to send a data from the C++ code to the QML model. After checking some posts, I came with this:

    //audiometadata.h
    #ifndef AUDIOMETADATA_H
    #define AUDIOMETADATA_H
    
    #include <QObject>
    
    class AudioMetadata : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(qint32 gAudioSongPlayedTime READ gAudioSongPlayedTime WRITE setGAudioSongPlayedTime NOTIFY gAudioSongPlayedTimeChanged)
        Q_PROPERTY(qint32 gAudioSongTotalTime READ gAudioSongTotalTime WRITE setGAudioSongTotalTime NOTIFY gAudioSongTotalTimeChanged)
    
    public:
        explicit AudioMetadata(QObject *parent = 0);
        ~AudioMetadata();
        qint32 gAudioSongPlayedTime();
        void setGAudioSongPlayedTime(qint32 value);
        qint32 gAudioSongTotalTime();
        void setGAudioSongTotalTime(qint32 value);
    
    signals:
        void gAudioSongPlayedTimeChanged();
        void gAudioSongTotalTimeChanged();
    
    private:
        qint32 m_audioSongPlayedTime;
        qint32 m_audioSongTotalTime;
    
    public slots:
    };
    
    #endif // AUDIOMETADATA_H
    
    //audiometadata.cpp
    #include "audiometadata.h"
    #include <QDebug>
    
    AudioMetadata::AudioMetadata(QObject *parent) : QObject(parent)
    {
        m_audioSongPlayedTime = 20;
        m_audioSongTotalTime = 100;
    }
    
    
    AudioMetadata::~AudioMetadata() {}
    
    
    qint32 AudioMetadata::gAudioSongPlayedTime()
    {
        return m_audioSongPlayedTime;
    }
    
    
    void AudioMetadata::setGAudioSongPlayedTime(qint32 value)
    {
        qDebug() << "Audio Song play time " << value;
        if(m_audioSongPlayedTime != value)
        {
            m_audioSongPlayedTime = value;
            qDebug() << "Audio Song play time " << m_audioSongPlayedTime;
            emit gAudioSongPlayedTimeChanged();
        }
        return;
    }
    
    
    qint32 AudioMetadata::gAudioSongTotalTime()
    {
        return m_audioSongTotalTime;
    }
    
    
    void AudioMetadata::setGAudioSongTotalTime(qint32 value)
    {
        if(m_audioSongTotalTime != value)
        {
            m_audioSongTotalTime = value;
            emit gAudioSongPlayedTimeChanged();
        }
        return;
    }
    
    //main.cpp
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QtQml>
    #include "audiometadata.h"
    
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        qmlRegisterType<AudioMetadata>("com.xequtor.cluster.audiometadata", 1, 0, "AudioMetadata");
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        AudioMetadata songData;
        songData.setGAudioSongTotalTime(320);
        songData.setGAudioSongPlayedTime(167);
    
        return app.exec();
    }
    
    //the .qml file, where I want to use the data
    import QtQuick 2.0
    import QtGraphicalEffects 1.0
    import com.xequtor.cluster.audiometadata 1.0
    
    Item {
        id: mediaContainer
        width: 400
        height: 768
    
        AudioMetadata {
            id: audioPlayerData
        }
    
        property string lAlbumArtGenericPath: "images/AUDIO_ALBUM_ART_GENERIC.png"
        property string gAlbumArtDynamicPath: "images/AUDIO_ALBUM_ART_DRE.png"
        property bool gAlbumArtAvailable: false
        property string gMetaDataTextLine1: "Dr. Dre feat. Snoop Dogg"
        property string gMetaDataTextLine2: "The Next Episode"
        property string gMetaDataTextLine3: "The Chronic"
        property int gCurrentSongTotalTime: audioPlayerData.gAudioSongTotalTime
        property int gCurrentSongPlayedTime: audioPlayerData.gAudioSongPlayedTime
        property string lCurrentSongTotalTime: "00:00"
    
    // .............. Some additonal code
    
     onGCurrentSongPlayedTimeChanged: {lCurrentSongTotalTime = getTrackTime(gCurrentSongPlayedTime); console.log(lCurrentSongTotalTime)}
    
    // ........... Some more code
    
     Text {
                    id: currentSongPlayedTime
                    anchors.verticalCenter: trackProgressContainer.verticalCenter
                    anchors.left: progressBarBackground.right
                    anchors.leftMargin: 20
                    width: 150
                    height: 20
                    horizontalAlignment: Text.AlignHCenter
                    verticalAlignment: Text.AlignVCenter
                    font.family: "Arial"
                    font.pointSize: 16
                    color: "#FFFFFF"
                    text: lCurrentSongTotalTime
                }
    

    I am able to get the data with the values from the class constructor (20 and 100). But when I create an object in the main.cpp file and call the WRITE functions from it, they are not updated in the qml model and the old values from the constructor (20 and 100) are still used. I saw in the console that the WRITE functions are called with the new values, but somehow they are not received by the QML model. What am I doing wrong? If you have a similar post or some complete example, which shows how is all this done, can you give me the link?

    Best Regards,
    Ahmed

    1 Reply Last reply
    0
    • S Offline
      S Offline
      stcorp
      wrote on last edited by stcorp
      #2

      I think it is because you create one object in the QML code, and another object in the C++ code. These are not the same object, and therefore do not share the same values for their properties.

      If you update the values from the QML, what happens then? So somewhere in the QML code, do audioPlayerData.gAudioSongPlayedTime = 666

      Maybe you could add a timer that sets gAudioSongPlayedTime, eg

      Timer
      {
          interval: 10
          repeat: true
          running: true
          onTriggered: audioPlayerData.gAudioSongPlayedTime = audioPlayerData.gAudioSongPlayedTime + 10
      }
      

      If this is the issue, and you need your object to be persistent, you might need to look into making it a singleton object: http://doc.qt.io/qt-5/qtqml-cppintegration-definetypes.html#registering-non-instantiable-types

      1 Reply Last reply
      1
      • DonCoderD Offline
        DonCoderD Offline
        DonCoder
        wrote on last edited by DonCoder
        #3

        Yes stcorp is correct, The object you are updating and the object you have in qml are different.

        you can either follow stcorp suggession. or you have to expose the object as context property as shown below and the same object you need to use in qml as well

            QGuiApplication app(argc, argv);
        
        //    qmlRegisterType<AudioMetadata>("com.xequtor.cluster.audiometadata", 1, 0, "AudioMetadata");
        
            QQmlApplicationEngine engine;
            engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        
            AudioMetadata songData;
            view.engine()->rootContext()->setContextProperty("songData", &songData);
            view.setSource(QUrl::fromLocalFile("MyItem.qml"));
        
        
            songData.setGAudioSongTotalTime(320);
            songData.setGAudioSongPlayedTime(167);
        
            return app.exec();
        
        
        1 Reply Last reply
        2
        • XequtorX Offline
          XequtorX Offline
          Xequtor
          wrote on last edited by
          #4

          Thanks for the answers, guys. I was able to send data from the C++ code to the QML. However, I still have some problems. I did the following:

          //main.cpp
          #include <QGuiApplication>
          #include <QQmlApplicationEngine>
          #include <QtQml>
          #include "audiometadata.h"
          
          
          int main(int argc, char *argv[])
          {
              QGuiApplication app(argc, argv);
              QQmlApplicationEngine engine;
              engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
          
              AudioMetadata songData;
              engine.rootContext()->setContextProperty("songData", &songData);
          
              songData.setGAudioSongTotalTime(320);
              songData.setGAudioSongPlayedTime(167);
          
              return app.exec();
          }
          
          //main.qml
          import QtQuick.Window 2.2
          import QtGraphicalEffects 1.0
          
          Window {
              id: window
              visible: true
              width: 1600
              height: 768
              color: "#000000"
              title: qsTr("Fancy Cluster")
          
          
              MouseArea {
                  anchors.horizontalCenter: parent.horizontalCenter
                  anchors.verticalCenter: parent.verticalCenter
                  onClicked: {
                      console.log(qsTr('Clicked on background. Text: "' + textEdit.text + '"'))
                  }
              }
          
              GaugeRTTs {
                  gRttCruiseControlMode: 5
                  gRttLeftTurnSignalMode: 2
                  gRttRightTurnSignalMode: 2
          
              }
          
              Information {
                  id: infoContainer
                  x: 1174
                  height: 768
                  anchors.right: parent.right
                  anchors.rightMargin: 0
              }
          
              Media {
                  id: mediaContainer
                  height: 768
                  anchors.left: parent.left
                  anchors.leftMargin: 0
          
                 gCurrentSongPlayedTime: songData.gAudioSongPlayedTime
                  gCurrentSongTotalTime: songData.gAudioSongTotalTime
              }
          
              Gauge {
                  anchors.horizontalCenter: parent.horizontalCenter;
                  anchors.verticalCenter: parent.verticalCenter
              }
          }
          

          Did not change anything else. Everything works fine, but I am getting ReferenceError: songData is not defined error in the beginning. How can this error be fixed?

          Also, is there any other way to communicate between C++ code and Qml and vice versa, or this is the only way?

          Best Regards,

          S 1 Reply Last reply
          0
          • XequtorX Xequtor

            Thanks for the answers, guys. I was able to send data from the C++ code to the QML. However, I still have some problems. I did the following:

            //main.cpp
            #include <QGuiApplication>
            #include <QQmlApplicationEngine>
            #include <QtQml>
            #include "audiometadata.h"
            
            
            int main(int argc, char *argv[])
            {
                QGuiApplication app(argc, argv);
                QQmlApplicationEngine engine;
                engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
            
                AudioMetadata songData;
                engine.rootContext()->setContextProperty("songData", &songData);
            
                songData.setGAudioSongTotalTime(320);
                songData.setGAudioSongPlayedTime(167);
            
                return app.exec();
            }
            
            //main.qml
            import QtQuick.Window 2.2
            import QtGraphicalEffects 1.0
            
            Window {
                id: window
                visible: true
                width: 1600
                height: 768
                color: "#000000"
                title: qsTr("Fancy Cluster")
            
            
                MouseArea {
                    anchors.horizontalCenter: parent.horizontalCenter
                    anchors.verticalCenter: parent.verticalCenter
                    onClicked: {
                        console.log(qsTr('Clicked on background. Text: "' + textEdit.text + '"'))
                    }
                }
            
                GaugeRTTs {
                    gRttCruiseControlMode: 5
                    gRttLeftTurnSignalMode: 2
                    gRttRightTurnSignalMode: 2
            
                }
            
                Information {
                    id: infoContainer
                    x: 1174
                    height: 768
                    anchors.right: parent.right
                    anchors.rightMargin: 0
                }
            
                Media {
                    id: mediaContainer
                    height: 768
                    anchors.left: parent.left
                    anchors.leftMargin: 0
            
                   gCurrentSongPlayedTime: songData.gAudioSongPlayedTime
                    gCurrentSongTotalTime: songData.gAudioSongTotalTime
                }
            
                Gauge {
                    anchors.horizontalCenter: parent.horizontalCenter;
                    anchors.verticalCenter: parent.verticalCenter
                }
            }
            

            Did not change anything else. Everything works fine, but I am getting ReferenceError: songData is not defined error in the beginning. How can this error be fixed?

            Also, is there any other way to communicate between C++ code and Qml and vice versa, or this is the only way?

            Best Regards,

            S Offline
            S Offline
            stcorp
            wrote on last edited by
            #5

            @Xequtor I think you need to set your context property after creating the QQmlApplicationEngine, but before loading main.qml. I'm not completely sure, but give it a try and see what happens

            1 Reply Last reply
            2
            • XequtorX Offline
              XequtorX Offline
              Xequtor
              wrote on last edited by
              #6

              Ah yeah, that was it. Thanks :)

              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