Search code examples
qtqmlqqmlengine

How to find out the QQmlEngine instance of a singleton object?


I have a class SingletonBaseClass that is defined in C++ and later extended in QML. In the qmldir file, it is marked as a Singleton:

// qmldir file
singleton SingletonClass 1.0 SingletonClass.qml

// SingletonClass.qml
import QtQml 2.0
pragma Singleton
SingletonBaseClass {
    // ...
}

This is the base class:

class SingletonBaseClass : public QObject 
{
    Q_OBJECT
    public:
    SingletonBaseClass(QObject* parent = nullptr) {}

    // Get the owner engine
    Q_INVOKABLE void someMethodCalledFromQml()
    {
        QQmlEngine* ownerEngine = ?
    }

    // Get the single instance of the given engine
    static SingletonBaseClass* instance(QQmlEngine* engine)
    {
        SingletonBaseClass* instance = ?
        return instance;
    } 

};
  1. How can I retrieve the QQmlEngine instance in SingletonBaseClass?
  2. How can I get a pointer to my singleton instance from within a static function?

Note: I have multiple QML engine instances in my application.

[Update]: I wasn't satisfied with the suggested workarounds and so I finally contributed this patch for 1. and QQmlEngine::singletonInstance() for 2. Both changes will be available in Qt 5.12.


Solution

  • If you want to get the QQmlEngine you can use the contextForObject() method as I show below:

    Q_INVOKABLE void someMethodCalledFromQml()
    {
        QQmlEngine *ownerEngine = QQmlEngine::contextForObject(this)->engine();
        qDebug()<<ownerEngine;
    }
    

    singletons in qml do not have a parent so a way to access them is by creating a property, for that we create a .qml and create an object with that property as the Singleton:

    qrc:/tmp.qml

    import QtQuick 2.0
    
    QtObject {
        property var obj: SingletonClass
    }
    

    and then this element is accessed by the following code:

    static SingletonBaseClass* instance(QQmlEngine* engine)
    {
        QQmlComponent component(engine, QUrl("qrc:/tmp.qml"));
        QObject *item = component.create();
        SingletonBaseClass *instance = qvariant_cast<SingletonBaseClass *>(item->property("obj"));
        return instance;
    }
    

    In the following link we show an example.