防止Qt中的射击信号

met*_*dos 52 c++ checkbox qt signals-slots

我们有一个QCheckBox对象,当用户检查它或删除检查时我们想要调用一个函数,所以我们将函数连接到stateChanged ( int state )signal.另一方面,根据某些条件,我们还会改变QCheckBox代码内部的对象状态,这会导致不需要的信号.

在某些情况下有没有办法防止发射信号?

Job*_*Job 78

您可以使用该clicked信号,因为它仅在用户实际单击复选框时发出,而不是在您使用手动检查时发出setChecked.

如果您只是不希望在特定时间发出信号,可以QObject::blockSignals像这样使用:

bool oldState = checkBox->blockSignals(true);
checkBox->setChecked(true);
checkBox->blockSignals(oldState);
Run Code Online (Sandbox Code Playgroud)

这种方法的缺点是所有信号都将被阻止.但我想这对于一个案例来说并不重要QCheckBox.

  • liaK提出的断开然后连接方案似乎比阻止此特定任务的所有信号更好. (4认同)
  • @Longfield:我认为使用`clicked`信号最适合这个特定的任务. (4认同)

Cal*_*itt 36

您始终可以使用阻止QObjects上的信号发射QObject::blockSignals().请注意,要正确处理事物,您应该记住旧状态(从函数调用返回),并在完成后恢复它.

在我的工作中,我们更喜欢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;
};
Run Code Online (Sandbox Code Playgroud)

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

  • 这取决于可能连接到对象信号的数量,您是否确定断开了相应的信号,以及重新连接它们是多么容易.我自己,我认为这通常更容易,但使用断开连接也可以. (6认同)
  • 这是在Qt5.3 QSignalBlocker中引入的:http://doc.qt.io/qt-5/qsignalblocker.html (5认同)
  • 遵循这种方式是否有任何具体原因?只是问B'cos我们习惯于在这些场景中使用`QObject :: disconnect()`. (2认同)
  • @liaK:一个很好的理由是 RAII,每个(每个)C++ 程序员都应该知道它,包括原因和方法。基本上,在这种情况下,即使抛出异常并且错过了手动解锁,它也会释放该块。就我个人而言,我使用类似的方法,我想知道为什么 Qt 的库中没有这个(或者我确实错过了它)。 (2认同)

lia*_*iaK 14

你可以QObject::disconnect删除相应的信号插槽连接,一旦你完成就可以QObject::connect 再次 ...


Boo*_*jum 12

在学习Qt时,我遇到了一系列互连的小部件,我想要"原子地"更新.我喜欢@ cjhuitt的解决方案,但发现基于代理对象的一些语法糖会更好.这是我用过的方法......

首先,我为阻止代理对象定义了一个类模板.像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; }
};
Run Code Online (Sandbox Code Playgroud)

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

template<class T> inline Blocker<T> whileBlocking(T *blocked) {
    return Blocker<T>(blocked);
}
Run Code Online (Sandbox Code Playgroud)

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

whileBlocking(checkBox)->setChecked(true);
Run Code Online (Sandbox Code Playgroud)

要么

whileBlocking(xyzzySpin)->setValue(50);
Run Code Online (Sandbox Code Playgroud)

这让我获得了RAII的所有好处,在方法调用周围自动配对阻塞和恢复,但我不需要命名任何包装器或状态标志.这很好,很简单,而且非常简单.


小智 6

QObject派生类中,您可以调用blockSignals(bool)以防止对象发出信号.例如:

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

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

  • 这不会阻止ui-> checkBox发出信号,因此它不会按预期工作.你应该调用ui-> checkBox-> blockSignals(true)或使用QSignalBlocker(从Qt5.3开始) (3认同)