防止Qt中的解雇信号

我们有一个QCheckBox对象,当用户检查它或删除检查我们要调用一个函数,所以我们把我们的函数连接到stateChanged ( int state )信号。 另一方面,根据一些条件,我们也改变了QCheckBox对象内部代码的状态,这就造成了不需要的信号。

有什么办法可以防止在某些情况下发射信号?

您可以使用clicked信号,因为只有当用户实际点击checkbox时才会发出信号,而不是使用setChecked手动检查它。

如果你不希望信号在特定时间发射,你可以使用如下的QObject::blockSignals

 bool oldState = checkBox->blockSignals(true); checkBox->setChecked(true); checkBox->blockSignals(oldState); 

这种方法的缺点是所有的信号都会被阻塞。 但是我想这在QCheckBox情况下并不重要。

您可以使用QObject::blockSignals()来始终阻止QObject上的信号发射。 请注意,对于事情是正确的,您应该记住旧的状态(从函数调用返回),并在完成后恢复。

在我的工作上,我们更喜欢RAII这种事情。 一个简单的类可能看起来像这样:

 class SignalBlocker { public: SignalBlocker( QObject *obj ) : m_obj( obj ), m_old( obj->blockSignals( true ) ) { } ~SignalBlocker() { m_obj->blockSignals( m_old ); } private: QObject *m_obj; bool m_old; }; 

编辑 :从Qt 5.3开始,请参阅QSignalBlocker (h / t到HappyCactus的评论)

你可以QObject::disconnect来删除相应的信号插槽连接,并可以QObject::connect一旦你完成QObject::connect

在学习Qt的过程中,我遇到了一些我想更新的“互相关联的小工具”。 我喜欢@ cjhuitt的解决scheme,但发现基于代理对象的一些语法糖更好。 这是我使用的方法…

首先,我为阻塞代理对象定义了一个类模板。 像迦勒的,这阻止build设的信号,然后恢复以前的状态在破坏。 但是,它也重载了->运算符来返回一个指向被阻止对象的指针:

 template<class T> class Blocker { T *blocked; bool previous; public: Blocker(T *blocked) : blocked(blocked), previous(blocked->blockSignals(true)) {} ~Blocker() { blocked->blockSignals(previous); } T *operator->() { return blocked; } }; 

接下来,我定义了一个小模板函数来构造并返回一个Blocker:

 template<class T> inline Blocker<T> whileBlocking(T *blocked) { return Blocker<T>(blocked); } 

把这一切放在一起,我会这样使用它:

 whileBlocking(checkBox)->setChecked(true); 

要么

 whileBlocking(xyzzySpin)->setValue(50); 

这使我获得了RAII的所有好处,在方法调用周围自动配对阻塞和恢复,但是我不需要命名任何包装器或状态标志。 这很好,很容易,而且相当干净。

QObject派生类中,可以调用blockSignals(bool)来防止对象发出信号。 举个例子:

 void customChangeState(bool checked) { blockSignals(true); ui->checkBox->setCheckState(Qt::Checked); // other work blockSignals(false); } 

上述方法将改变检查状态,而不用点击, stateChanged或任何其他信号发射。

Qt5.3引入了QSignalBlocker类,它以一种exception安全的方式完成所需的工作。

 if (something) { const QSignalBlocker blocker(someQObject); // no signals here } 

即使在QT5中,当有很多/几件事情要封锁的时候,它也有点麻烦。 这是一个简洁的多对象版本:

 class SignalBlocker { public: SignalBlocker(QObject *obj) { insert( QList<QObject*>()<<obj ); } SignalBlocker(QList<QObject*> objects) { insert(objects); } void insert(QList<QObject*> objects) { for (auto obj : objects) m_objs.insert(obj, obj->signalsBlocked()); blockAll(); } void blockAll() { for( auto m_obj : m_objs.keys() ) m_obj->blockSignals(true); } ~SignalBlocker() { for( auto m_obj : m_objs.keys() ) m_obj->blockSignals( m_objs[m_obj] ); } private: QMap<QObject*,bool> m_objs; }; 

用法:

 void SomeType::myFunction() { SignalBlocker tmp( QList<QObject*>() << m_paramWidget->radioButton_View0 << m_paramWidget->radioButton_View1 << m_paramWidget->radioButton_View2 ); // Do more work, ... } 

当某个UI元素不应答用户时,可以将其禁用。 所以用户会知道这个元素不接受input。