C++ 防止在 Qt 中触发信号
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3556687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Prevent Firing Signals in Qt
提问by metdos
We have a QCheckBox
object, when user checks it or removes check we want to call a function so we connect our function to stateChanged ( int state )
signal. On the other hand, according to some condition we also change the state of QCheckBox
object inside code, and this causes the unwanted signal.
我们有一个QCheckBox
对象,当用户检查它或删除检查时,我们想要调用一个函数,因此我们将我们的函数连接到stateChanged ( int state )
信号。另一方面,根据某些情况,我们也会改变QCheckBox
代码内部对象的状态,这会导致不需要的信号。
Is there any way to prevent firing signal under some conditions?
在某些情况下有什么办法可以防止发射信号?
回答by Job
You can use the clicked
signal because it is only emitted when the user actually clicked the check box, not when you manually check it using setChecked
.
您可以使用该clicked
信号,因为它仅在用户实际单击复选框时才会发出,而不是在您使用setChecked
.
If you just don't want the signal to be emitted at one specific time, you can use QObject::blockSignals
like this:
如果您只是不想在某个特定时间发出信号,则可以这样使用QObject::blockSignals
:
bool oldState = checkBox->blockSignals(true);
checkBox->setChecked(true);
checkBox->blockSignals(oldState);
The downside of this approach is that allsignals will be blocked. But I guess that doesn't really matter in case of a QCheckBox
.
这种方法的缺点是所有信号都将被阻止。但我想这在 a 的情况下并不重要QCheckBox
。
回答by Caleb Huitt - cjhuitt
You can always block signal emission on QObjects using QObject::blockSignals()
. Note that to be correct about things, you should remember the old state (returned from the function call), and restore it when you are done.
您始终可以使用 阻止 QObjects 上的信号发射QObject::blockSignals()
。请注意,要正确处理事情,您应该记住旧状态(从函数调用返回),并在完成后恢复它。
At my job, we prefer RAII for this sort of thing. A simple class to do so might look like this:
在我的工作中,我们更喜欢使用 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;
};
Edit: Starting with Qt 5.3, see QSignalBlocker(h/t to HappyCactus in comments)
编辑:从 Qt 5.3 开始,请参阅QSignalBlocker(h/t to HappyCactus 在评论中)
回答by liaK
You can QObject::disconnect
to remove the corresponding signal-slot connection and can QObject::connect
againonce you are done...
您可以QObject::disconnect
删除相应的信号槽连接,完成后可以QObject::connect
再次...
回答by Boojum
While learning Qt, I ran into this problem with a set of interconnected widgets that I wanted to update "atomically". I liked @cjhuitt's solution, but found that it goes even better with a bit of syntactic sugar based on proxy objects. Here's the approach that I used...
在学习 Qt 时,我遇到了一组互连小部件的问题,我想“以原子方式”更新这些小部件。我喜欢@cjhuitt 的解决方案,但发现它在使用基于代理对象的一些语法糖时效果更好。这是我使用的方法...
First, I defined a class template for a blocker proxy object. Like Caleb's, this blocks the signals on construction, and then restores their previous state on destruction. However, it also overloads the ->
operator to return a pointer to the blocked object:
首先,我为拦截器代理对象定义了一个类模板。像 Caleb 一样,这会在构建时阻塞信号,然后在销毁时恢复它们之前的状态。但是,它也会重载->
运算符以返回指向阻塞对象的指针:
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; }
};
Next, I defined a small template function to construct and return a Blocker:
接下来,我定义了一个小的模板函数来构造并返回一个 Blocker:
template<class T> inline Blocker<T> whileBlocking(T *blocked) {
return Blocker<T>(blocked);
}
Putting this all together, I'd use it like this:
将所有这些放在一起,我会像这样使用它:
whileBlocking(checkBox)->setChecked(true);
or
或者
whileBlocking(xyzzySpin)->setValue(50);
This gets me all the benefits of RAII, with automatically paired blocking and restore around the method call, but I don't need to name any wrapper or state flags. It's nice, easy, and pretty darn foolproof.
这让我获得了 RAII 的所有好处,在方法调用周围自动配对阻塞和恢复,但我不需要命名任何包装器或状态标志。这很好,很简单,而且非常万无一失。
回答by ZestyMeta
In QObject
derived classes, you can call blockSignals(bool)
to prevent the object from emitting signals. So for example:
在QObject
派生类中,您可以调用blockSignals(bool)
以防止对象发出信号。例如:
void customChangeState(bool checked)
{
blockSignals(true);
ui->checkBox->setCheckState(Qt::Checked);
// other work
blockSignals(false);
}
The above method would change the check state without clicked, stateChanged
, or any other signals being emitted.
上述方法将更改检查状态,而无需单击stateChanged
、 或任何其他信号被发射。
回答by HappyCactus
Qt5.3 introduced the QSignalBlockerclass that does exactly what needed in an exception safe way.
Qt5.3 引入了QSignalBlocker类,该类以异常安全的方式完成所需的工作。
if (something) {
const QSignalBlocker blocker(someQObject);
// no signals here
}
回答by peter karasev
Even in QT5, its a bit cumbersome when there are many/several things to block. Here's a multi-object version that is concise to use:
即使在 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;
};
usage:
用法:
void SomeType::myFunction()
{
SignalBlocker tmp( QList<QObject*>()
<< m_paramWidget->radioButton_View0
<< m_paramWidget->radioButton_View1
<< m_paramWidget->radioButton_View2
);
// Do more work, ...
}
回答by user2524405
When some UI element should not respond to user it is appropriate to disable it. So that user would know that this element is not accepting input.
当某些 UI 元素不应响应用户时,禁用它是合适的。这样用户就会知道这个元素不接受输入。