防止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。