I was wondering either there is a possibility in Qt, co create a signal-slot connection, that will automatically break all other connections to this particular slot/ signal? I would appreciate all help.
3 Answers
Qt doesn't provide such functionality directly. Moreover, it's impossible to iterate signal-slot connections, so you can't even implement it yourself in general.
What you should be doing is keeping track of the connections that you initiate yourself, and removing them as appropriate.
For example:
enum class ConnectionDisposal { Dispose, Keep };
class UniqueConnector {
Q_DISABLE_COPY(UniqueConnector)
QMetaObject::Connection m_conn;
ConnectionDisposal m_cd;
public:
explicit UniqueConnector(ConnectionDisposal cd = ConnectionDisposal::Dispose) :
m_cd(cd) {}
~UniqueConnector() { if (m_cd == ConnectionDisposal::Dispose) disconnect(); }
template <typename T, typename R>
QMetaObject::Connection connect(const QObject * tx, T txf,
const QObject * rx, R rxf,
Qt::ConnectionType type = Qt::AutoConnection) {
QObject::disconnect(m_conn);
return m_conn = QObject::connect(tx, txf, rx, rxf, type);
}
template <typename T, typename R>
QMetaObject::Connection connect(const QObject * tx, T txf, R rxf) {
QObject::disconnect(m_conn);
return m_conn = QObject::connect(tx, txf, rxf);
}
bool disconnect() { return QObject::disconnect(m_conn); }
};
The UniqueConnector
allows only one connection to exist on its instance. So, for each unique connection, you need one UniqueConnector
instance. The connection is removed upon destruction of the connector, unless you specify otherwise.

- 95,931
- 16
- 151
- 313
So, you can use following scenario:
if (!connect(senderObject, SIGNAL(signalName()), receiverObject, SLOT(slotName()), Qt::UniqueConnection))
{
QMetaObject::disconnect(senderObject, senderObject->metaObject()->indexOfSignal(SIGNAL(signalName())),
NULL, receiverObject->metaObject()->indexOfSlot(SLOT(slotName())));
connect(senderObject, SIGNAL(signalName()), receiverObject, SLOT(slotName()));
}

- 1,088
- 6
- 16
-
1But what you have shown is done by `Qt::Uniqueconnection` itself. WHat did you mean? – Łukasz Przeniosło Jul 23 '15 at 17:24
-
As far as I know `Qt::UniqueConnection` just return false, if this connection already has. – timocov Jul 23 '15 at 17:32
-
Was not me. But in this examle I dont know either other connections exist. I am wondering either there is a method to disconnect everything I dont know about. – Łukasz Przeniosło Jul 23 '15 at 17:38
-
1In this case you can use `QObject::disconnect(someObject, SIGNAL(signalName()), 0, 0)`. – timocov Jul 23 '15 at 17:41
I wrote this function very quickly and tested it, it seems that it really works! Yes, algorithm is not perfect, it probably can be improved, but it requires more time. Try this solution and tell result:
QMetaObject::Connection uniqueConnect(const QObject *sender, const char *signal, const QObject *receiver , const char *slot, Qt::ConnectionType type = Qt::AutoConnection)
{
const QMetaObject * metaSender = sender->metaObject();
const QMetaObject * metaReceiver = receiver->metaObject();
int signalIndex = metaSender->indexOfSignal(signal);
int slotIndex = metaReceiver->indexOfSlot(slot);
//iterate throw all methods! and discover only signals and slots
for (int i = 0; i < metaSender->methodCount(); ++i)
{
for (int j = 0; j < metaReceiver->methodCount(); ++j)
{
if(metaSender->method(i).methodType() == QMetaMethod::Signal)
{
if(metaReceiver->method(j).methodType() == QMetaMethod::Slot)
{
//immitate SIGNAL SLOT macro, see more in the end of the answer.
QByteArray finalSignal = "2" + metaSender->method(i).methodSignature();
QByteArray finalSlot = "1" + metaReceiver->method(j).methodSignature();
QObject::disconnect(sender,finalSignal.data(),receiver,finalSlot.data());
}
}
}
}
return QObject::connect(sender,signal,receiver,slot,type);
}
Test:
QObject *obj = new QObject;
connect(obj,SIGNAL(objectNameChanged(QString)),this,SLOT(testFunc()));
connect(obj,SIGNAL(destroyed()),this,SLOT(testFunc()));
obj->setObjectName("newNAme");
uniqueConnect(obj,SIGNAL(objectNameChanged(QString)),this,SLOT(showMaximized()));
obj->setObjectName("more");
Output:
testFunc called once!!!
...maximized window...
-
This of works. The cost is O(N^2), so it has to be kept in mind if you have lots of signals or slots. It also doesn't support connections to functors. It's better to track the connections yourself, though, since you're the one who set the connections to start with. – Kuba hasn't forgotten Monica Jul 23 '15 at 17:48
-
@KubaOber Yes, I agree with you. That's why I said that algorithms is not perfect, about another: I first of all tried to use Qt introspection and didn't remember about more generic way as you provided in your answer. – Jablonski Jul 23 '15 at 17:58
-
Sure, I think it's a good answer too, since it shows that you can't iterate the connections, and the best you can do (if you don't have the connection handle) is to iterate all possible connection kinds, and attempt to remove them individually. This is an acceptable workaround for existing code that wasn't changed yet to use a connection tracker. – Kuba hasn't forgotten Monica Jul 23 '15 at 18:34