Qt Unique Connection
Qt does not provide this functionality directly. Moreover, it is not possible to iterate over the signal slot connections, so you cannot implement it yourself at all.
What you should do is keep track of those connections that you initiate yourself and remove them as needed.
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); }
};
UniqueConnector
allows only one connection to be used on its instance. Thus, you need one instance for each unique connection UniqueConnector
. The connection is removed when the connector is destroyed, unless you specify otherwise.
source to share
I wrote this function very quickly and tested it, it seems like it actually works! Yes, the algorithm is not perfect, it can probably be improved, but it takes more time. Try this solution and report the 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...
source to share
So, you can use the following script:
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()));
}
source to share