-
作用
bool QObject::blockSignals(bool block)
可锁定/解锁对象的信号。 -
使用
常用于限制信号的发送, 一般加锁和解锁成对出现。 如
ui->comboBox->blockSignals(true);
ui->comboBox->setCurrentIndex(3);
ui->comboBox->blockSignals(false);
因为如果不先锁定信号,直接调用setCurrentIndex,则会触发comboBox的currentIndexChanged信号。
- QT内部实现
实质上是修改了一个标志位:blockSig
bool QObject::blockSignals(bool block) noexcept
{
Q_D(QObject);
bool previous = d->blockSig;
d->blockSig = block;
return previous;
}
在事件循环的时候,会判断此标志位:
template <bool callbacks_enabled>
void doActivate(QObject *sender, int signal_index, void **argv)
{
QObjectPrivate *sp = QObjectPrivate::get(sender);
if (sp->blockSig)
return;
...
发送信号
}
- 其他
在函数的说明文档中提到:
Note that the destroyed() signal will be emitted even if the signals for this object have been blocked.
意为 即使此对象锁定了信号,也会发送destroyed() 信号。
查看源码可得知,在object析构函数中,会先去将上述标志位改为false,这样就不会拒绝信号的发送。
QObject::~QObject()
{
Q_D(QObject);
d->wasDeleted = true;
d->blockSig = 0; // unblock signals so we always emit destroyed()
QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
if (sharedRefcount) {
if (sharedRefcount->strongref.loadRelaxed() > 0) {
qWarning("QObject: shared QObject was deleted directly. The program is malformed and may crash.");
// but continue deleting, it's too late to stop anyway
}
// indicate to all QWeakPointers that this QObject has now been deleted
sharedRefcount->strongref.storeRelaxed(0);
if (!sharedRefcount->weakref.deref())
delete sharedRefcount;
}
if (!d->isWidget && d->isSignalConnected(0)) {
emit destroyed(this);
}
...
}
- 关于QSignalBlocker
使用QSignalBlocker类可替代blockSignals函数,防止锁定之后忘记解锁导致没有信号发出。
QSignalBlocker内部实现了构造时加锁,析构时解锁(RAII思想)
QSignalBlocker::QSignalBlocker(QObject *o) noexcept
: m_o(o),
m_blocked(o && o->blockSignals(true)),
m_inhibited(false)
{}
QSignalBlocker::~QSignalBlocker()
{
if (m_o && !m_inhibited)
m_o->blockSignals(m_blocked);
}
从源码中得知,其内部仍然调用的是blockSignals。