I am writing an application in Qt. I am trying to create a system of signals and slots to connect a single controller thread to multiple threads which represent real-life devices. The number of devices is known at compile-time, but I would like it to be as easy as possible to change the number of them. My initial approach used templates on the signals, something like this:
signals:
template<int whichOne> void updateDoohickeyState(dooHickeyState newState);
My hope was that I could then connect these to the devices like so:
connect(doohickeyController, doohickeyController::updateDoohickeyState<0>,
doohickeys[0], doohickeyObject::updateState,
Qt::QueuedConnection);
connect(doohickeyController, doohickeyController::updateDoohickeyState<1>,
doohickeys[1], doohickeyObject::updateState,
Qt::QueuedConnection);
// Etc...
Then, when I wanted to signal a device, I could do something like:
emit updateDoohickeyState<0>(doohickeyState);
emit updateDoohickeyState<1>(anotherDoohickeyState);
Unfortunately, Qt's MOC does not support templates on signals and slots; therefore, this does not work.
So, how else can I implement this? I have one controller which needs to signal to particular one of multiple identical devices in other threads. I would ideally like to do so without adding more signals (more complicated to update later), filtering slot-side (inefficient) or adding another class in the middle.
You can invoke an object's slot directly using QMetaObject::invokeMethod instead of connected signal emission. Like this:
QMetaObject::invokeMethod(doohickeys[0], "updateState", Qt::QueuedConnection, Q_ARG(dooHickeyState, doohickeyState));
QMetaObject::invokeMethod(doohickeys[1], "updateState", Qt::QueuedConnection, Q_ARG(dooHickeyState, anotherDoohickeyState));
It sounds like you might want a pub/sub service. It's quite easy to implement it in Qt using signals/slots and and a Q_Object for the service.
Related
I am new to QT. As far as I can see, there are two ways to connect signals and slots with each other. One way would be using the connect method. When e.g. wanting to put a method ButtonReleased() to the slot that is triggered after the released() signal of a pushButton with name pushButton, one could write:
connect(ui->pushButton, SIGNAL(released()), this, SLOT(ButtonPressed()));
However, as far as I see, one could also define a method with name on_pushButton_released() to achieve the same connection. Is there any difference between both methods and if so, which one is preferred?
Thanks in advance!
There are indeed two main ways to connect signals to slots.
The first one, using the connect method allows to connect any signal to any slot (or signal) as long as the function signatures match. This is the main way to connect signals in Qt.
The second way are member methods that are called on_ObjectName_SignalName(). These are automatically connected by Qt, if a UI element called ObjectName exists and has a signal called SignalName. This is specifically meant for the use case of having some Widget with a separate .ui file, which contains these elements that you want to connect to. As such, this mechanism does not work if you create UI elements "by hand" in your C++ code.
As you can see, the second mechanism has very specific requirements that need to be satisfied to work, although these are not uncommon. So if you have satisfied these conditions I see no Problem in doing it this way, but others may disagree and this is largely personal preference.
Also note: The syntax in your question is the old syntax from Qt4. If you are using Qt5 and newer, it is highly advised to use the new syntax.
You can read more about signals and slots on the Qt Documentation.
I have the follow constellation:
A qt gui thread with MainWindow
Another thread which essentially is a CameraManager...everytime a camera is added/removed the MainWindow will be informed.
It roughly looks like this:
Mainwindow derives from ICameraAddedConsumer
MainWindow implements ConsumeCameraAdded and creates widget inside this function. It subscribes itselv as a consumer to the CameraManager
CameraManager calls ConsumeCameraAdded of all it's consumers (MainWindow) when a new camera is added.
The problem is that CameraManager lives in a different thread and Qt will obviously complain about this since a widget is not created in the same thread as the mainwindow was.
Any suggestions how I can solve this?
As per comments, using signals/slots between QObjects in different threads should take care of the issue "automagically."
Barring that, and assuming MainWindow/ICameraAddedConsumer is a QObject, one idea could be to use something like:
QMetaObject::invokeMethod(consumer, "ConsumeCameraAdded", Qt::QueuedConnection, ...)
where consumer is a pointer to the MainWindow/ICameraAddedConsumer instance.
There's QWaitCondition but I'm not sure that makes sense in this case (though it could be adapted I suppose).
Otherwise... don't create the widget in ConsumeCameraAdded() but set some flag there (and return) and then use a QTimer or QObject::timerEvent() to periodically check the flag and create widget if it is set. Unfortunately I'm pretty sure you will not be able to create or start a timer within ConsumeCameraAdded() itself because of threading issues.
I have a QObject class processing requests. So I could create a SLOT process(QString). I would like to know when the request was processed - i.e. receive a future of some kind that I can wait for. It should be possible to relate reults to corresponding requests.
But since the SLOT can't return a value, I'm a bit stuck... Can this be achieved with the Qt SIGNAL/SLOT mechanism?
Your slot can emit a signal when it is done (with any data you need as arguments) that you can then connect to, to do other stuff at that point.
I know that normally you wouldn’t do what I’m asking. I understand that these two layers should be separate and connect via signal/slot mechanism, which maybe asynchronous if we deal with threads.
Understanding this, I still need to call qml signal handler synchronously from SG thread. Qml objects live in GUI thread, thus emitting a signal from SG thread (particularly from updatePaintNode() method) results in asynchronous event.
I have read docs and I have no problem calling qml function synchronously from cpp from another thread. For example:
QMetaObject::invokeMethod(this, "myNiceQmlFunction", Qt::DirectConnection);
But imagine this:
//some.cpp
signal void callQmlHandler();
//some.qml
MyObject {
onCallQmlHandler: {
// do something right now
}
}
I don’t know how to call onCallQmlHandler synchronously via QMetaObject::invokeMethod.
I don’t create qml object from code and at this point in cpp I don’t have access to qml component to look for its children, find MyObject there by name and call its handler (if it is possible). Anyways, this is not a beautiful way to do so.
I tried to find signal handler among QMetaObject methods, but it's not there. Nor it is in properties list (I checked just in case, because syntax of signal handlers is similar to property's one)
Does anyone know if I miss the right syntax to call signal handler via QMetaObject::invokeMethod or it is not possible at all? Any ideas?
You can pass a C++ object to QML using its context.
qmlviewer.rootContext()->setContextProperty("backend", backend);
QML side:
Connections {
target: backend
onCallQmlHandler: {
// do something right now
}
}
When you emit callQmlHandler from backend object, you get the handler executed.
But Connections object may create queued connections, so you can implement your own DirectConnections. At the end of this post you have an implementation.
However QML is excecuted by a QML engine, which I think is intended to be run by a single thread, so you may run into a bigger problem unless you really know what you are doing!
I have something like the following design of classes and I'm wondering if it's OK that I use many signal slot connections to communicate between them. There is a MainWindow class which holds all the GUI, then a Wrapper class, which provides an interface to the back-end, then there is a Controller class for spawning and managing threads and finally there are Workers which do all the work.
Now let's say I'm loading a file and want to display progress using a progress bar in the MainWindow. My Worker class sends updateProgress(int progress) to Controller::handleProgress(int progress) slot which again sends progress signal to the Wrapper class, which in return sends a progress signal to the main window, which finally updates the progress bar.
Similarly when the data has been loaded it is processed in the Wrapper class and, again, communicated through signals and slots (although with one less step).
Is it a standard way of doing things in Qt or should I rethink my design?
It is a valid possibility.
Note that Qt allows you to go even further and do the following:
QObject::connect(&sender, SIGNAL(mySenderSignal(int)),
&receiver, SIGNAL(myReceiverSignal(int));
That's right, you can bind a signal to a signal. All it does can be seen as "when the sender's signal is emitted, emit the receiver's signal".
If you don't have any specific task to perform in your intermediary slots, that might save you a few lines, while showing exactly what you're doing: you're "forwarding" a signal. Otherwise, if you must absolutely do work in between, then you must keep the signals and the slots.
Note that you still have to be sure that the signals signatures match.