Sometimes it's useful to establish a connection between a signal and a slot that should be activated only once. This is not how signal/slot connections normally behave. Remember that, when a connection is established, it will stay active until:
- the connection is explicitly disconnected; or
- the sender object is destroyed; or
- the receiver object is destroyed.
So, if we need such a single-shot connection, how do we go about it? A possible solution is to connect our signal to a small helper function (for instance, a lambda) that disconnects the connection, then calls the actual slot. This is it, in pseudocode:
There's a semantic problem with this code: the connection
object is created after the lambda. But we need its value in the lambda, to be able to disconnect it! Fixing this requires us to introduce a little indirection, but it's doable:
This is...quite annoying to write. I certainly don't want to type all of that every time I need a single-shot connection, and trying to make it generic is super tricky for new users of Qt.
We can do better!
Enter Qt 6.0!
In Qt 6, I have added the convenience Qt::SingleShotConnection
connection flag that you can pass as the fifth argument of QObject::connect (optionally combining it with the other connection types):
The static_cast
isn't technically necessary, in this case. But it becomes necessary, should we want to also pass some other arguments (for instance, if we want the connection to be queued as well as single-shot). This closed a long-standing and very voted feature request. Sometimes, by removing the pebble in your shoe, you make many other people happy.
And for Qt 5?
I can't add the same feature to Qt 5, as Qt 5 development is closed for new features.
However, I've also reimplemented the solution shown above in KDToolBox and packaged it with a convenient API:
KDToolBox is KDAB's collection of miscellaneous useful C++ classes and stuff. You can download it from our GitHub repository here.
Have fun!
Trusted software excellence across embedded and desktop platforms
The KDAB Group is a globally recognized provider for software consulting, development and training, specializing in embedded devices and complex cross-platform desktop applications. In addition to being leading experts in Qt, C++ and 3D technologies for over two decades, KDAB provides deep expertise across the stack, including Linux, Rust and modern UI frameworks. With 100+ employees from 20 countries and offices in Sweden, Germany, USA, France and UK, we serve clients around the world.
3 Comments
16 - Apr - 2021
Kelteseth
So this is like QTimer::singleShot()?
16 - Apr - 2021
Giuseppe D'Angelo
Hello,
I'm not sure what you mean. Could you elaborate, how would you use singleShot to achieve the same result?
2 - Dec - 2021
Y Malaika
I don't think so.
QTimer::singleshot() invokes the slot without establishing a connection, either immediately or with a specified delay.
What is presented here are ways to establish a latent, single use only connection without invoking it. When and if it does get invoked, at some currently unspecified time by some currently unspecified signal, it will automatically disconnect itself from that signal. Neither the sender nor the receiver need be aware of this or have their code burdened by it, and that means you are free to place the entirety of the glue logic somewhere else should you desire to do so. At least that's my understanding.