61

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

在某些情况下有什么方法可以防止触发信号吗?

4

8 回答 8

92

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

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

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

这种方法的缺点是所有信号都会被阻塞。但我想在QCheckBox.

于 2010-08-24T13:13:33.920 回答
37

您始终可以使用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;
};

编辑:从 Qt 5.3 开始,请参阅QSignalBlocker (h/t to HappyCactus in comments)

于 2010-08-24T13:26:49.300 回答
16

在学习 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; }
};

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

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

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

whileBlocking(checkBox)->setChecked(true);

或者

whileBlocking(xyzzySpin)->setValue(50);

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

于 2014-06-22T08:10:03.843 回答
14

您可以QObject::disconnect删除相应的信号槽连接,并在完成QObject::connect 后再次...

于 2010-08-24T13:18:23.440 回答
6

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

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

上述方法将更改检查状态,而stateChanged不会发出单击、 或任何其他信号。

于 2010-08-24T13:26:28.693 回答
4

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

if (something) {
   const QSignalBlocker blocker(someQObject);
   // no signals here
}
于 2015-04-17T09:45:09.460 回答
0

即使在 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, ... 
}
于 2015-07-13T03:14:47.510 回答
-1

当某些 UI 元素不应该响应用户时,禁用它是合适的。这样用户就会知道这个元素不接受输入。

于 2013-06-26T13:52:19.050 回答