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.


  • Moderators

    @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.


  • Moderators

    @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 to null 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
    

  • Banned

    This post is deleted!

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.