0

I am having a problem understanding how to use a c++ singleton object from qml. I know that I have to inherit my classes from the QObject class and that I have to expose the properties. And that in order for them to be usable in the qml I have to do setContextProperty("ClassName", &class name).

However, if we admit that this class contains another object and that I want to be able to use it from the qml, I get errors like "cannot call method name" from undefined object.

Example:

APi.h

 class API : public QObject {
  Q_OBJECT
  Q_PROPERTY(User *user READ getUser WRITE setUser NOTIFY userChanged)
public:
  Q_INVOKABLE inline User *getUser() const {
    qDebug() << "get called";
    return user;
  };
  inline void setUser(User *new_user) { this->user = new_user; };

signals:
  void userChanged();

private:
  User *user;
};

User.h

#ifndef USER_H
#define USER_H

#include <QObject>
#include <QString>

class User: public QObject{
Q_OBJECT
public:
    Q_INVOKABLE inline QString &getName(){return name;}; // qrc:/main.qml:63: TypeError: Cannot call method 'getName' of undefined
private:
    QString name;
};
#endif // USER_H

main.cpp

#include <QQmlContext>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtQuick3D/qquick3d.h>
#include "API.h"
#include "User.h"

int main(int argc, char *argv[]) {
  QGuiApplication app(argc, argv);
  QQmlApplicationEngine engine;
  API api;
  User user;
  api.setUser(&user);
  engine.rootContext()->setContextProperty("API", &api);

  qmlRegisterType<User>("User", 1, 0, "User");

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

  return app.exec();
}

main.qml

import QtQuick
import QtQuick3D
import QtQuick.Controls
import QtQuick.Layouts

Window {

    Item{
        id: test
        Component.onCompleted: {
            console.log("Completed")
            API.getUser() // no error, getUser is called without error
            console.log(API.getUser().getName())
        }
    }
}

What possibilities do I have to access the User object from the qml through API?

3
  • 1
    Please tighten up your example (use the edit button) to remove typo's like Q_Object. Commented Jan 17, 2022 at 22:07
  • 1
    Your example is not complete. Please provide a minimal reproducible example. As an example of why this is needed, you aren't showing us where you are loading your qml. Commented Jan 17, 2022 at 22:41
  • OK, I edited it and created a simple reproducible example as you intented for Commented Jan 17, 2022 at 23:26

1 Answer 1

1

You could do any of the following:

Add a public slot in API class:

API.cpp:
QString API::getUserName()
{
    return user.getName();
}

main.qml:
Component.onCompleted: console.log( API.getUserName() )

Make User a Q_PROPERTY in API class:

API.h:
Q_PROPERTY( User* user READ user NOTIFY userChanged)

main.qml:
Component.onCompleted: console.log( API.user.getName() )

Register User with QML:

main.cpp:
qmlRegisterType<User>("MyUser", 1, 0, "MyUser");

main.qml:
Component.onCompleted: console.log( API.getUser().getName() )
Sign up to request clarification or add additional context in comments.

1 Comment

Ok perfect, the second one is what I looking for. But I noticed that I can't used &getName cause of the reference instead of it just use getName

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.