Problem with Singleton: Why isn't it unique?
-
I want to define a Singleton component as a dispatcher of signals. For example, I to call a function on the Singleton from somewhere in a QML file (let's say
function1()
) and emit a signal from inside that Singleton (let's saymySignal()
).I should then be able to connect to the signal from another QML file completely.
I'll upload a simple example tomorrow that shows this. It does work as expected.
But then when I implement that functionality in another codebase, the second QML component is not able to receive the signal from the singleton. When I print the singleton, I get different "addresses":
qml: ### ActionSingleton.qml -- this: ActionSingleton_QMLTYPE_71(0x14e5a10) qml: ### OtherComponent.qml -- ActionSingleton: ActionSingleton_QMLTYPE_89(0x31b2f20)
I expected both to print the same values (the simple example does print the same value).
My code is different from the minimal, simple example, but I don't what could be that different. I mean, a singleton should be a singleton, however the code is organized? I do have a
pthread
in the code for another event loop (for network communications). Could that be interfering? I'm also using cmake (version qmake on the simple example).I'm really out of ideas! Any suggestions?
Thanks!
-
Hi! Please post a minimal yet complete example so others can reproduce this / see what's going wrong.
-
@Wieland Sorry I had to leave yesterday and even had to rush the post.
Here's a minimal working example:
https://github.com/nbigaouette/qml-singleton-issue
(see tagminimal_working_example
at commit 5fb24ab84c0f969ddba5973acf7bbaff4ae717c9 for the working version).Actually, it contains a working example showing what I want to achieve. The problem is that when I integrate this into my codebase, it does not work anymore; I have multiple singleton! I'll try to modify the working example in a way to "break" it and show the same (wrong) behaviour.
Meanwhile, do you have an idea as to why a singleton might have multiple instances? Could threading creating a second one? Anything else?
Thanks!
-
Playing with the example code I was able to identify the issue.
The
minimal_working_example
contains the simplest, working example of what I want to achieve.In the
problematic
branch I added the different modifications required to make the code look exactly the way it was done in the "real" code base, one small commit at a time.After a while, I realized that the
MyComponentOne.qml
andMyComponentTwo.qml
'sConnections
stopped working: those components could not receive thefunc2
signal emitted by the singleton (even if there was no error): The signal handlersonFunc2
defined in theMyComponentOne.qml
andMyComponentTwo.qml
are never receiving any signals!Thanks to git bisect, I identified commit 5b1db19a47192b78bb49f773b213ca5c29e2f6eb as the bad one:
git show 5b1db19a47192b78bb49f773b213ca5c29e2f6eb commit 5b1db19a47192b78bb49f773b213ca5c29e2f6eb Author: Nicolas Bigaouette <nbigaouette@gmail.com> Date: Fri Jun 17 10:03:11 2016 -0400 Use "///" instead of "/" when loading main.qml diff --git a/simple/src/main.cpp b/simple/src/main.cpp index 21e3b00..1424282 100644 --- a/simple/src/main.cpp +++ b/simple/src/main.cpp @@ -6,7 +6,7 @@ int main(int argc, char *argv[]) QGuiApplication app(argc, argv); QQmlApplicationEngine engine; - engine.load(QUrl("qrc:/qml/main.qml")); + engine.load(QUrl("qrc:///qml/main.qml")); return app.exec(); }
After that commit, I did:
- Compile and run
- Click blue rectangle (load
MyComponentOne.qml
) - Click cyan rectangle (call
MySingleton.func1()
) - Click red rectangle (load
MyComponentTwo.qml
) - Click cyan rectangle (call
MySingleton.func1()
)
and the output is as follow:
qml: # MySingleton.qml::func1() - MySingleton: MySingleton_QMLTYPE_0(0x224dd10) qml: # MySingleton.qml::onFunc2() - MySingleton: MySingleton_QMLTYPE_0(0x224dd10) qml: # MySingleton.qml::func1() - MySingleton: MySingleton_QMLTYPE_0(0x224dd10) qml: # MySingleton.qml::onFunc2() - MySingleton: MySingleton_QMLTYPE_0(0x224dd10)
Note how
onFunc2
is only triggered for the singleton and not for theMyComponent*.qml
.After reverting 5b1db19a47192b78bb49f773b213ca5c29e2f6eb (resulting in adcfaa35d1ec3546b4d2a2d4494bc01c0cc63983) I get the proper behaviour:
qml: # MySingleton.qml::func1() - MySingleton: MySingleton_QMLTYPE_0(0x25a3810) qml: # MySingleton.qml::onFunc2() - MySingleton: MySingleton_QMLTYPE_0(0x25a3810) qml: # MyComponentOne.qml::onFunc2() - MySingleton: MySingleton_QMLTYPE_0(0x25a3810) qml: # MySingleton.qml::func1() - MySingleton: MySingleton_QMLTYPE_0(0x25a3810) qml: # MySingleton.qml::onFunc2() - MySingleton: MySingleton_QMLTYPE_0(0x25a3810) qml: # MyComponentTwo.qml::onFunc2() - MySingleton: MySingleton_QMLTYPE_0(0x25a3810)
So the problem was how the
main.qml
file is loaded from C++!Wrong:
engine.load(QUrl("qrc:///qml/main.qml"));
Good:
engine.load(QUrl("qrc:/qml/main.qml"));
I don't know why the code was using "///" instead of "/"...