qtqmlqt-quickqproperty

How to update qml text from two different cpp?


I have an qml project.

There is a text(named id:cnt) on StackPage.qml and I need to update this text from firstclass.cpp and secondclass.cpp.

Q_PROPERTY defines are on firstclass.h and setCntText function is on firstclass.cpp.

I update the text from firstclass.cpp by setCntText(i) and try to update from secondclass.cpp by calling setCntText(0).

I can set the m_cntText variable from secondclass but couldnt update qml text(named id:cnt).

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "firstclass.h"
#include "secondclass.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    firstClass frmFirstClass;
    engine.rootContext()->setContextProperty("frmFirstClass",&frmFirstClass);

    secondClass frmSecondClass;

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

firstclass.cpp

#include "firstclass.h"

firstClass::firstClass(QObject *parent) : QObject(parent)
{
    QTimer *timer1 = new QTimer();
    connect(timer1, &QTimer::timeout, [=]() {setter1();});
    timer1->start(2000);
}

int firstClass::cntText() const
{
    return m_cntText;
}

void firstClass::setCntText(int cntText)
{
    if (m_cntText == cntText)
        return;

    m_cntText = cntText;
    emit cntTextChanged(m_cntText);
}

void firstClass::setter1()
{
    static int i = 0;
    i++;
    qDebug() <<"counter1 : " << i;
    setCntText(i);
}

secondclass.cpp

#include "secondclass.h"

firstClass frmFirstClass;

secondClass::secondClass(QObject *parent) : QObject(parent)
{
    QTimer *timer = new QTimer();
    timer->setSingleShot(true);
    timer->start(1000);

    connect(timer, &QTimer::timeout, [=]() {
        QTimer *timer2 = new QTimer(this);
        connect(timer2,SIGNAL(timeout()),this,SLOT(setter2()));
        timer2->start(2000);
        timer->deleteLater();
    } );
}

void secondClass::setter2()
{
    frmFirstClass.setCntText(0);
    qDebug() << "Checking m_cntText = " << frmFirstClass.m_cntText;
}

firstclass.h

#ifndef FIRSTCLASS_H
#define FIRSTCLASS_H

#include <QObject>
#include <QTimer>
#include <QDebug>

class firstClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int cntText READ cntText WRITE setCntText NOTIFY cntTextChanged)


public:
    explicit firstClass(QObject *parent = nullptr);

    int cntText() const;

    int m_cntText;

signals:

    void cntTextChanged(int cntText);

public slots:

    void setCntText(int cntText);

private slots:

    void setter1();
};

#endif // FIRSTCLASS_H

secondclass.h

#ifndef SECONDCLASS_H
#define SECONDCLASS_H

#include <QObject>
#include <QTimer>
#include <QDebug>
#include "firstclass.h"

extern firstClass frmFirstClass;

class secondClass : public QObject
{
    Q_OBJECT

private:

public:
    explicit secondClass(QObject *parent = nullptr);

signals:

public slots:

private slots:

    void setter2();
};

#endif // SECONDCLASS_H

main.qml

import QtQuick 2.10
import QtQuick.Window 2.12
import QtQuick.Controls 2.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Rectangle{
        anchors.fill: parent
        color: "black"

        StackView{
            anchors.fill: parent
            initialItem : stackPage
        }

        Component{
            id:stackPage
            StackPage{}
        }
    }
}

StackPage.qml

import QtQuick 2.0

Item {

    Rectangle{
        anchors.centerIn: parent
        width: 200
        height: 200
        color: "orange"

        Text {
            id: cnt
            text: frmFirstClass.cntText
            verticalAlignment: Text.AlignVCenter
            horizontalAlignment: Text.AlignHCenter
            font.pointSize: 40
            anchors.fill: parent
        }

    }

}

Solution

  • Your extern usage is incomplete, so you are effectively creating two instances of firstClass. As extern is a bit misleading at poitns, I suggest you to give a pointer to the "one-and-only" firstClass when creating secondClass (in main). This also gives the code a better representation of intended hierarchy.

    Update the following files:

    secondClass.h

    #include "firstClass.h"
    
    class secondClass : public QObject
    {
        Q_OBJECT
    
        private:
    
        public:
            explicit secondClass(firstClass *theFirstClass, QObject *parent = nullptr);
    
        signals:
    
        public slots:
    
        private slots:
    
            void setter2();
    
        private:
            firstClass *myFirstClass_ = nullptr;
    };
    

    secondClass.cpp

    #include "secondclass.h"
    
    secondClass::secondClass(firstClass *theFirstClass, QObject *parent) 
        : QObject(parent)
        , myFirstClass(theFirstClass)
    {
        QTimer *timer = new QTimer();
        timer->setSingleShot(true);
        timer->start(1000);
    
        connect(timer, &QTimer::timeout, [=]() {
            QTimer *timer2 = new QTimer(this);
            connect(timer2,SIGNAL(timeout()),this,SLOT(setter2()));
            timer2->start(2000);
            timer->deleteLater();
        } );
    }
    
    void secondClass::setter2()
    {
        myFirstClass->setCntText(0);
        qDebug() << "Checking m_cntText = " << myFirstClass->m_cntText;
    }
    

    main.cpp

    int main(int argc, char *argv[])
    {
        ...
    
        firstClass frmFirstClass;
        engine.rootContext()->setContextProperty("frmFirstClass", &frmFirstClass);
    
        secondClass frmSecondClass(&frmFirstClass);
    
        ...
    }
    

    Disclaimer: I did not try to compile this