c++qtqmlqproperty

Qt: ERROR in Exposing C++ Class to QML


I keep getting the same error when I run the application:

qrc:/main.qml:13: ReferenceError: _myClass is not defined

Where is the bug?

Furthermore, if I want to connect signal myIntChanged to a slot, where should I place my connect? In main.cpp or in constructor MyClass?

myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H

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

class MyClass : public QObject
{
    Q_OBJECT

public:
    MyClass(QObject *parent = 0);

    Q_PROPERTY(int myInt READ getMyInt WRITE setMyInt NOTIFY myIntChanged)
    int myInt;
    inline int getMyInt() { return myInt; }
    inline void setMyInt(int _value) { myInt = _value; }

private:
    void initVariables();

    QTimer *timer;

private slots:
    void editVariables();

signals:
    void myIntChanged();
};

#endif // MYCLASS_H

myclass.cpp

#include "myclass.h"

MyClass::MyClass(QObject *parent) : QObject (parent)
{
    initVariables();

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(editVariables()));
    timer -> start(3000);
}

void MyClass::initVariables()
{
    myInt = 0;
}

void MyClass::editVariables()
{
    myInt = myInt + 1;

    qDebug() << "myclass.cpp: timeout: variables edited.";
}

main.cpp

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

#include "myclass.h"

int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QGuiApplication app(argc, argv);

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

    MyClass *myClass = new MyClass();
    engine.rootContext() -> setContextProperty("_myClass", myClass);

    return app.exec();
}

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Exposed C++ Class")

    Text {
        anchors.top: parent.top; anchors.topMargin: 30
        anchors.left: parent.left; anchors.leftMargin: 30
        text: _myClass.myInt
    }
}

Solution

  • The problem is caused because with the load() statement being loading the .qml file, when reading it and verifying if the variables exist, they realize that this object does not exist since it is passed to them through setContextProperty(), a possible solution is to pass the object to it before it loads the .qml:

    int main(int argc, char *argv[])
    {
    #if defined(Q_OS_WIN)
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    #endif
    
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        MyClass *myClass = new MyClass();
        engine.rootContext()->setContextProperty("_myClass", myClass);
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;
        return app.exec();
    }
    

    It is not updated because it has not been notified through the signals that you have declared, the correct thing to do is to emit a signal every time the property changes, you must modify some methods:

    inline void setMyInt(int _value) {
        if(myInt == _value)
            return;
        myInt = _value;
        emit myIntChanged();
    }
    

    void MyClass::editVariables()
    {
        setMyInt(getMyInt()+1);
        qDebug() << "myclass.cpp: timeout: variables edited.";
    }