我想知道是否有可能在Qt,共同创建一个信号槽连接,这将自动打破所有其他连接到这个特定的槽/信号?
Qt不直接提供这样的功能。此外,迭代信号槽连接是不可能的,所以你甚至不能自己实现它。
你应该做的是跟踪你自己发起的连接,并在适当的时候删除它们。
例如: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
只允许在其实例上存在一个连接。因此,对于每个唯一连接,您需要一个UniqueConnector
实例。除非您另有指定,否则在连接器被破坏时将删除连接。
那么,您可以使用以下场景:
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()));
}
我很快地写了这个函数并测试了它,看起来它真的有效!是的,算法并不完美,它可能可以改进,但这需要更多的时间。尝试这个解决方案并告诉结果:
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);
}
测试:
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");
输出:testFunc called once!!!
...maximized window...
如何模拟SIGNAL SLOT宏