Re: [Interest] QML Singleton and QTimer?
> Sent: Monday, May 10, 2021 at 3:08 AM > From: "Ulf Hermann" > To: interest@qt-project.org > Subject: Re: [Interest] QML Singleton and QTimer? > > Hi, > > > GuiApplication::GuiApplication(int argc, char*argv[]): > > QGuiApplication::QGuiApplication(argc, argv) > > { > > m_hardwareInterface = new HardwareInterface; > > qmlRegisterSingletonInstance("com.company", 1, 0, "HardwareInterface", > > m_hardwareInterface); > > } > > qmlRegisterSingletonInstance() is dangerous if you create your singleton > in a different thread than the one the QML engine runs on. The QML > engine expects to be able fiddle with internals of those objects via the > metaobject system. > > It also does surprising things when you have multiple QML engines: The > first one to access it grabs the objects and all others only see null. > > It also does not play ball with qmlRegisterTypesAndRevisions() the way I > had intended. You cannot register an instance before the type because > the type will then get rejected. You also cannot register an instance > after the type because there is no way to hook into the type > registration procedure without providing some kind of callback. If you > could provide a callback, then that would be pretty much the same as > providing a factory function, though. > > The whole qmlRegisterSingletonInstance() was a mistake, sorry about > that. It's too easy to shoot yourself in the foot with it and there is > no way to make its type visible at compile time. You should really use > the QML_SINGLETON macro and let the QML engine handle the life cycle of > the object. The QML engine will make sure to create and destroy it on > the right thread. qmlRegisterSingletonInstance() will be deprecated > before Qt 7. It definitely seems that way! I hope this can be added to the documentation to avoid other people going down this path? I was eager to finally use it, as it would have simplified things on my side. But it looks like it is a difficult thing to wield properly. ___ Interest mailing list Interest@qt-project.org https://lists.qt-project.org/listinfo/interest
Re: [Interest] QML Singleton and QTimer?
Hi, GuiApplication::GuiApplication(int argc, char*argv[]): QGuiApplication::QGuiApplication(argc, argv) { m_hardwareInterface = new HardwareInterface; qmlRegisterSingletonInstance("com.company", 1, 0, "HardwareInterface", m_hardwareInterface); } qmlRegisterSingletonInstance() is dangerous if you create your singleton in a different thread than the one the QML engine runs on. The QML engine expects to be able fiddle with internals of those objects via the metaobject system. It also does surprising things when you have multiple QML engines: The first one to access it grabs the objects and all others only see null. It also does not play ball with qmlRegisterTypesAndRevisions() the way I had intended. You cannot register an instance before the type because the type will then get rejected. You also cannot register an instance after the type because there is no way to hook into the type registration procedure without providing some kind of callback. If you could provide a callback, then that would be pretty much the same as providing a factory function, though. The whole qmlRegisterSingletonInstance() was a mistake, sorry about that. It's too easy to shoot yourself in the foot with it and there is no way to make its type visible at compile time. You should really use the QML_SINGLETON macro and let the QML engine handle the life cycle of the object. The QML engine will make sure to create and destroy it on the right thread. qmlRegisterSingletonInstance() will be deprecated before Qt 7. best, Ulf ___ Interest mailing list Interest@qt-project.org https://lists.qt-project.org/listinfo/interest
Re: [Interest] QML Singleton and QTimer?
Hi, Is your QTimer access before the QGuiApplication is created (static singleton)? That could explain why this complain and moving the singleton instance into the GuiApplcation constructor solve your problems. What we do over here, I have a custom template method that register the singleton from Qml and from C++ singleton class (templated too). This keep a map of type and pointer to object: typedef QMap>> SingletonMapType; extern SingletonMapType singleton_instances_map_; after that the C++ singleton fetch into that map and so does my Qml singleton register type, so I get a single instance no matter who the C++ or the Qml request the singleton first. It might not be ideal, but it work well. So they are not really a static instance but instead a version that is kept based on the current QQmlEngine and application. If your application only use a single QQmlengine (like most of them do, you can skip the first layer of the map and simply use the map from string to QObject. For the QString you can extract it from template type and T::staticMetaObject.className() you only need a getSingleton() and a createSingleton() class to fill the blank. So my class are not bake with singleton, there might be an instance that is singleton instead (make it easier to test the class without enforcing singleton into it and I can still make memento and the like of those object without being screw to have only hard single copy. Jérôme Godbout, B. Ing. Software / Firmware Team Lead O: (418) 682-3636 ext.: 114 C: (581) 777-0050 godbo...@dimonoff.com<mailto:godbo...@dimonoff.com> [signature_75730]<https://www.dimonoff.com/> dimonoff.com<https://www.dimonoff.com/> 1015 Avenue Wilfrid-Pelletier, Québec, QC G1W 0C4, 4e étage From: Jason H Date: Friday, May 7, 2021 at 10:10 AM To: Jérôme Godbout Cc: interestqt-project.org Subject: Re: [Interest] QML Singleton and QTimer? Well, the documentation gives the example of the singleton being instantiated at the main.cpp:main() level. It felt a little wrong, but I subclassed QGuiApplication, and created and registered the singleton there: GuiApplication::GuiApplication(int argc, char*argv[]): QGuiApplication::QGuiApplication(argc, argv) { m_hardwareInterface = new HardwareInterface; qmlRegisterSingletonInstance("com.company", 1, 0, "HardwareInterface", m_hardwareInterface); } This seems to work, but seemed unnatural. Sent: Thursday, May 06, 2021 at 5:42 PM From: "Jérôme Godbout" To: "Jason H" , "interestqt-project.org" Subject: Re: [Interest] QML Singleton and QTimer? You can check the thread affinity of an object and the current thread that will display the problem you encounter. Use a queued signal into the QTimer thread to sent the start (it will be delayed until the thread process the event, hopefully you do no need precision there). Jérôme Godbout, B. Ing. Software / Firmware Team Lead O: (418) 682-3636 ext.: 114 C: (581) 777-0050 godbo...@dimonoff.com<mailto:godbo...@dimonoff.com> [signature_93124102]<https://www.dimonoff.com/> dimonoff.com<https://www.dimonoff.com/> 1015 Avenue Wilfrid-Pelletier, Québec, QC G1W 0C4, 4e étage From: Interest on behalf of Jason H Date: Thursday, May 6, 2021 at 5:34 PM To: interestqt-project.org Subject: [Interest] QML Singleton and QTimer? I'm trying to have a simple singleton class, but it doesn't appear that I can use timers? HardwareInterface::HardwareInterface(QObject *parent) : QObject(parent) { m_timer = new QTimer(this); connect(m_timer, ::timeout, this, [=](){ qDebug() << Q_FUNC_INFO; }); m_timer->start(100); // QObject::startTimer: Timers can only be used with threads started with QThread } main.cpp: int main() { ... qmlRegisterSingletonInstance("com.company.example", 1, 0, "HardwareInterface", ); ... How do we go about using timers in singletons? ___ Interest mailing list Interest@qt-project.org https://lists.qt-project.org/listinfo/interest ___ Interest mailing list Interest@qt-project.org https://lists.qt-project.org/listinfo/interest
Re: [Interest] QML Singleton and QTimer?
Well, the documentation gives the example of the singleton being instantiated at the main.cpp:main() level. It felt a little wrong, but I subclassed QGuiApplication, and created and registered the singleton there: GuiApplication::GuiApplication(int argc, char*argv[]): QGuiApplication::QGuiApplication(argc, argv) { m_hardwareInterface = new HardwareInterface; qmlRegisterSingletonInstance("com.company", 1, 0, "HardwareInterface", m_hardwareInterface); } This seems to work, but seemed unnatural. Sent: Thursday, May 06, 2021 at 5:42 PM From: "Jérôme Godbout" To: "Jason H" , "interestqt-project.org" Subject: Re: [Interest] QML Singleton and QTimer? You can check the thread affinity of an object and the current thread that will display the problem you encounter. Use a queued signal into the QTimer thread to sent the start (it will be delayed until the thread process the event, hopefully you do no need precision there). Jérôme Godbout, B. Ing. Software / Firmware Team Lead O: (418) 682-3636 ext.: 114 C: (581) 777-0050 godbo...@dimonoff.com dimonoff.com 1015 Avenue Wilfrid-Pelletier, Québec, QC G1W 0C4, 4e étage From: Interest on behalf of Jason H Date: Thursday, May 6, 2021 at 5:34 PM To: interestqt-project.org Subject: [Interest] QML Singleton and QTimer? I'm trying to have a simple singleton class, but it doesn't appear that I can use timers? HardwareInterface::HardwareInterface(QObject *parent) : QObject(parent) { m_timer = new QTimer(this); connect(m_timer, ::timeout, this, [=](){ qDebug() << Q_FUNC_INFO; }); m_timer->start(100); // QObject::startTimer: Timers can only be used with threads started with QThread } main.cpp: int main() { ... qmlRegisterSingletonInstance("com.company.example", 1, 0, "HardwareInterface", ); ... How do we go about using timers in singletons? ___ Interest mailing list Interest@qt-project.org https://lists.qt-project.org/listinfo/interest ___ Interest mailing list Interest@qt-project.org https://lists.qt-project.org/listinfo/interest
Re: [Interest] QML Singleton and QTimer?
You can check the thread affinity of an object and the current thread that will display the problem you encounter. Use a queued signal into the QTimer thread to sent the start (it will be delayed until the thread process the event, hopefully you do no need precision there). Jérôme Godbout, B. Ing. Software / Firmware Team Lead O: (418) 682-3636 ext.: 114 C: (581) 777-0050 godbo...@dimonoff.com<mailto:godbo...@dimonoff.com> [signature_93124102]<https://www.dimonoff.com/> dimonoff.com<https://www.dimonoff.com/> 1015 Avenue Wilfrid-Pelletier, Québec, QC G1W 0C4, 4e étage From: Interest on behalf of Jason H Date: Thursday, May 6, 2021 at 5:34 PM To: interestqt-project.org Subject: [Interest] QML Singleton and QTimer? I'm trying to have a simple singleton class, but it doesn't appear that I can use timers? HardwareInterface::HardwareInterface(QObject *parent) : QObject(parent) { m_timer = new QTimer(this); connect(m_timer, ::timeout, this, [=](){ qDebug() << Q_FUNC_INFO; }); m_timer->start(100); // QObject::startTimer: Timers can only be used with threads started with QThread } main.cpp: int main() { ... qmlRegisterSingletonInstance("com.company.example", 1, 0, "HardwareInterface", ); ... How do we go about using timers in singletons? ___ Interest mailing list Interest@qt-project.org https://lists.qt-project.org/listinfo/interest ___ Interest mailing list Interest@qt-project.org https://lists.qt-project.org/listinfo/interest
[Interest] QML Singleton and QTimer?
I'm trying to have a simple singleton class, but it doesn't appear that I can use timers? HardwareInterface::HardwareInterface(QObject *parent) : QObject(parent) { m_timer = new QTimer(this); connect(m_timer, ::timeout, this, [=](){ qDebug() << Q_FUNC_INFO; }); m_timer->start(100); // QObject::startTimer: Timers can only be used with threads started with QThread } main.cpp: int main() { ... qmlRegisterSingletonInstance("com.company.example", 1, 0, "HardwareInterface", ); ... How do we go about using timers in singletons? ___ Interest mailing list Interest@qt-project.org https://lists.qt-project.org/listinfo/interest