Qt Unique Connection

I was wondering if there is a possibility in Qt to create a signal-slot connection that will automatically break all other connections to that particular slot / signal? I would appreciate everyone's help.

+3


source to share


3 answers


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.

+4


source


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

      

How to import SIGNAL SLOT macro.

+1


source


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()));
}

      

0


source







All Articles