How do I implement a singleton provider for qmlRegisterSingletonType?

I want to use C ++ classes as Singleton instances in QML and figured I needed to register them in the qmlRegisterSingletonType. This function requires a function that provides an instance of a registered C ++ class. I am using latest Qt 5.3.1 with MinGW 4.8 enabled for 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 an out-of-class function like this in a header, appearing in another cpp file, including the same header:

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

      

Also, it's just plain wrong to write a singleton provider that returns a new instance when called from different cpp files. So I tried my own implementation, where I use a static member of the class to return an 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 log this with ...

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

      

This solution also doesn't work, I get linker errors:

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

      

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

Why does the example suggest creating a new instance every time the provider function is called?

+5


source to share


3 answers


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

Quoting from the documentation for the function qmlRegisterSingletonType

:

NOTE. The QObject singleton instance returned by the singleton provider belongs to the QML engine. For this reason, a singleton type provider function should not be implemented as a singleton type factory.

This means that this behavior, when a singleton type provider returns a new instance, is done on purpose, even though, as you may have noticed, it looks strange at first glance. So, your class implementation should look something like this:



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 must use the ampersand for MySingleton::qmlInstance

, since it is a member method. See this for more information. Then the registration should look like this:

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

      

+11


source


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



QObject * MySingleton::m_instance = 0;

      

+1


source


If you want to call this singleton class also from C ++, please change the line

return new MySingleton;

      

in

return new &MySingleton;

      

-3


source







All Articles