Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a singleton provider for qmlRegisterSingletonType?

Tags:

c++

qt

qml

I want to use C++ Classes as Singleton instances in QML and figured that I have to register them with qmlRegisterSingletonType. This function requires a function which provides an instance of the registered C++ class. I am using latest Qt 5.3.1 with included MinGW 4.8 on Windows.

The documentation shows the following example of a provider function:

static QJSValue example_qjsvalue_singletontype_provider(QQmlEngine *engine, 
    QJSEngine *scriptEngine)
{
    Q_UNUSED(engine)

    static int seedValue = 5;
    QJSValue example = scriptEngine->newObject();
    example.setProperty("someProperty", seedValue++);
    return example;
}

I tried to use this, but I get a compiler warning when I define such a function outside of class scope in a header, occurring in another cpp file including the same header:

warning: 'QObject* example_qjsvalue_singletontype_provider(QQmlEngine*, 
QJSEngine*)' defined but not used [-Wunused-function]

Furtheron, it just feels wrong to write a singleton provider which returns a new instance when called from different cpp files. So I tried an own implementation where I use a static class member to return the instance:

// mysingleton.h
class MySingleton: public QObject
{
    Q_OBJECT
    Q_DISABLE_COPY(MySingleton)
public:
    static QObject *qmlInstance(QQmlEngine *engine, QJSEngine *scriptEngine) {

        Q_UNUSED(engine)
        Q_UNUSED(scriptEngine)

        if(!m_instance)
        {
            m_instance = new MySingleton();
        }
        return m_instance;
    }
    MySingleton(QObject* parent = 0)
        :QObject(parent)
    {}
private:
    static QObject* m_instance;
};

I tried to register this using ...

qmlRegisterSingletonType<MySingleton>(uri, 1, 0, "MySingleton", 
MySingleton::qmlInstance);

This solution doesn't work either, I am getting linker errors:

release/main.o:main.cpp:
(.text$_ZN11MySingleton11qmlInstanceEP10QQmlEngineP9QJSEngine[__ZN11MySingleton11
qmlInstanceEP10QQmlEngineP9QJSEngine]+0x42): undefined reference to 
`MySingleton::m_instance'

What is the correct solution to provide the required Singleton instance 1) with a function outside of class scope and 2) with a class member function?

Why does the example suggest to create a new instance on every call of the provider function?

like image 255
FourtyTwo Avatar asked Aug 20 '14 11:08

FourtyTwo


2 Answers

it just feels wrong to write a singleton provider which returns a new instance when called from different cpp files. So I tried an own implementation where I use a static class member to return the instance

Quote from documentation to qmlRegisterSingletonType function:

NOTE: A QObject singleton type instance returned from a singleton type provider is owned by the QML engine. For this reason, the singleton type provider function should not be implemented as a singleton factory.

It means that such behaviour when singleton type provider returns a new instance is done by intention despite the fact that it, as you have noted, looks weird at first glance. So, your class implementation should look something like below:

class MySingleton: public QObject
{
    Q_OBJECT
    Q_DISABLE_COPY(MySingleton)

    MySingleton() {}

public:
    static QObject *qmlInstance(QQmlEngine *engine, QJSEngine *scriptEngine)
    {
        Q_UNUSED(engine);
        Q_UNUSED(scriptEngine);

        return new MySingleton;
    }
};

Moreover, you should use ampersand for MySingleton::qmlInstance since it is a member method. See this for more info. Then registration should look so:

qmlRegisterSingletonType<MySingleton>(uri, 1, 0, "MySingleton", &MySingleton::qmlInstance);
like image 178
Dmitry Volosnykh Avatar answered Sep 28 '22 19:09

Dmitry Volosnykh


The problem is (your second example) that you have to initialize your m_instance static member variable. You can do it in mysingleton.cpp file, like:

QObject * MySingleton::m_instance = 0;
like image 24
vahancho Avatar answered Sep 28 '22 18:09

vahancho