How to write a signal router?
-
Hi,
I'm currently using QT 5.5.1. and I have the following problem:
I have a signal dispatcher (SD) object that can be connected to, at most three objects. It is supposed to work in the mode:
if (object1 is present and able to process the output signal) activate the signal to object1
else if (object2 is present and able to process the output signal) activate the signal to object2
else activate the signal to object3.Object1 and Object 2 are not always present. Moreover Object1 is "volatile". I.e. it created and deleted regularly. And object2 is in fact a family of objects (there is 30 different "object2". Only one is connected at a time).
So, I have currently developped an approach with three group of output signals (one by possible object). And, each object performs a connect when needed, and a disconnect when it is no more active. So, to determine if an output signal is connected I expected to use QObject::isSignalConnected.
Unfortunately this approach does not work for two reasons:
1- isSignalConnected return true when a connection has been created, even after a disconnect. I have found a bug report from 2013 about this strange behavior. This bug report is marked as "reported", and nothing has been done, even in documentation, to solve it,
2- It appears that "disconnect" does not delete the connection. It just set to null the pointer to the receiver. This means that my connect/disconnect approach risks to generate a big list of useless connections that will slow down the application. That is not acceptable.So, does someone has an idea to solve my problem?
Thanks a lot in advance.
-
@Alain38 said in How to write a signal router?:
So, to determine if an output signal is connected I expected to use QObject::isSignalConnected
you can try to use
QObject::connectNotify()
/QObject::disconnectNotify()
instead -
@raven-worx Thanks. I will have to manage manually connections. At least it can solve my first problem. I still have the second problem, that is the increasing number of useless connection objects.
-
@Alain38 said in How to write a signal router?:
2- It appears that "disconnect" does not delete the connection. It just set to null the pointer to the receiver. This means that my connect/disconnect approach risks to generate a big list of useless connections that will slow down the application. That is not acceptable.
are you sure about that?
I think i remember slightly that it is set tonull
upon disconnect, but the list is cleaned-up at some point later when the list is traversed. -
@raven-worx I discovered the problem in the following scheme:
connection of an object as "object2"
Connection of an object as "object1"
Disconnection of object1
Disconnection of object2
Connection of a new object2. This last one did not receive the signal. So I have followed the signal under the debug. And I have seen that I still have two connections with no receiver. I think connections are only deleted when the sender is deleted. But in my case it is still present (it is the SD). -
@raven-worx I confirm. I implemented your proposal and did a lot of operations. Number of connections without receiver increases each time.
-
OK. I found a solution. For this I'm mimicking the connection process. My SD has an attribute
QMap < ObjectType, QMap < QObject *, QMap<QString, QString> > > m_objectLists;
two members:
//----------------------------------------------------------------------------------- void CommunicationManager::registerObject(ObjectType p_type, QObject *p_object, const QMap<QString, QString> &p_connections) //----------------------------------------------------------------------------------- {// registerObject(...) m_objectLists[p_type][p_object] = p_connections; }// registerObject(...) //----------------------------------------------------------------------------------- void CommunicationManager::unregisterObject(ObjectType p_type, QObject *p_object) //----------------------------------------------------------------------------------- {// unregisterObject(ObjectType p_type, QObject *p_object) if (!m_objectLists[p_type].value(p_object).isEmpty()) {// Right unregister object m_objectLists[p_type].remove(p_object); }// Right unregister object }// unregisterObject(ObjectType p_type, QObject *p_object)
and the following signals:
void sigAccept(); void sigReject(); void sigStartAcquire(); void sigStopAcquire(); void sigQuit();
Then an object needs to connect to the SD it calls registerObject by indicating the correspondance between the SD signals and its signals/slots (see example below):
QMap<QString, QString> connections; connections["sigAccept"] = "accept"; connections["sigReject"] = "reject"; CommunicationManager::s_instance.registerObjectCommunicationManager::POPUP, this, connections);
Finally the processing of events received by the SD is performed by the following function:
//----------------------------------------------------------------------------------- void CommunicationManager::slotEventReceived(Event p_event) //----------------------------------------------------------------------------------- {// slotEventReceived(Event p_event) QMap<QObject *, QMap<QString, QString> > popupConnections = m_objectLists.value(POPUP ); QMap<QObject *, QMap<QString, QString> > unitConnections = m_objectLists.value(UNIT ); QMap<QObject *, QMap<QString, QString> > appConnections = m_objectLists.value(APPLICATION); bool eventProcessed = false; switch (p_event) {// Process the eventQ case ACCEPT: // Check pop-up for (auto connections = popupConnections.begin(); connections != popupConnections.end(); ++connections) {// Check if something is connected QMap<QString, QString> connectionList = connections.value(); if (connectionList.value("sigAccept") != "" ) {// Something is connected QMetaObject::invokeMethod(connections.key(), connectionList["sigAccept"].toStdString().c_str(), Qt::AutoConnection); eventProcessed = true; }// Something is connected }// Check if something is connected if (!eventProcessed) {// Check current unit for (auto connections = unitConnections.begin(); connections != unitConnections.end(); ++connections) {// Check if something is connected QMap<QString, QString> connectionList = connections.value(); if (connectionList.value("sigAccept") != "") {// Something is connected QMetaObject::invokeMethod(connections.key(), connectionList["sigAccept"].toStdString().c_str(), Qt::AutoConnection); eventProcessed = true; }// Check if something is connected }// Check if something is connected }// Check current unit if (!eventProcessed) {// Check application for (auto connections = appConnections.begin(); connections != appConnections.end(); ++connections) {// Check if something is connected QMap<QString, QString> connectionList = connections.value(); if (connectionList.value("sigAccept") != "" ) {// Something is connected QMetaObject::invokeMethod(connections.key(), connectionList["sigAccept"].toStdString().c_str(), Qt::AutoConnection); eventProcessed = true; }// Check if something is connected }// Check if something is connected }// Check application break; and so on for the others events
-
This post is deleted!
-
If you got the solution then please share with me also. Check this 192-168-1-1ip it might help everyone.