How to implement a singleton provider for qmlRegisterSingletonType?
Solution 1
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);
Solution 2
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;
Comments
-
FourtyTwo about 2 years
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?
-
FourtyTwo over 9 yearsI never saw the second code snippet in real code. What does this actually do?
-
Bob over 4 yearsWhere in the docs does it say you have to or even can template the call
qmlRegisterSingletonType
? -
Dmitry Volosnykh over 4 years@Bob I have update the link to point to a correct method overload.