修改更改相关项目信息的文本框(QLineEdit)时如何避免无限循环?

How can I avoid infinite loop when modifying textboxes (QLineEdit) that change related item info?

我在一个小部件中有几个字段,每个字段都会影响一个项目的行为,更改其中的一些会改变其他的。

我在某处读到,行编辑的 editingFinished() 信号仅由用户操作触发 - 而不是由代码更改触发...是真的吗?

connect(m_lineEdit1, SIGNAL(editingFinished()), this, SLOT(m_lineEdit1Changed()));
connect(m_lineEdit2, SIGNAL(editingFinished()), this, SLOT(m_lineEdit2Changed()));

connect(this, SIGNAL(someSignal()), this, SLOT(updateData()));

void m_lineEdit1Changed()
{
    changedata1();
    emit someSignal();
}

void m_lineEdit2Changed()
{
    changedata2();
    emit someSignal();
}

void updateData()
{
    m_lineEdit1.setText(fromdata);
    m_lineEdit2.setText(fromdata);
}

如果我更改 m_lineEdit1,并更新整个小部件(通过代码更改 m_lineEdit2),我会在 m_lineEdit2Changed()

中设置断点

这会导致更新的无限循环...

我该怎么做才能避开它?

避免此问题的一种方法是使用 QObject::blockSignals() 函数。

在你的例子中你会做:

void updateData()
{
    m_lineEdit1.blockSignals(true);
    m_lineEdit1.setText(fromdata);
    m_lineEdit1.setText(fromdata);
    m_lineEdit1.blockSignals(false);
}

当您在行编辑中更改数据时,blockSignals() 调用会阻止对象发送任何信号。

阻塞信号是一种有点像大锤的方法。您可以使用哨兵 class 来显式防止递归:

#define SENTINEL_STRINGIFY(x) #x
#define SENTINEL_TOSTRING(x) SENTINEL_STRINGIFY(x)
#define SENTINEL_AT __FILE__ ":" SENTINEL_TOSTRING(__LINE__)

class Sentinel {
  Q_DISABLE_COPY(Sentinel);
  static QMutex m_mutex;
  static QSet<QString> m_sentinels;
  QString const m_sentinel;
  bool const m_ok;
  static bool checkAndSet(const QString & sentinel) {
    QMutexLocker lock(&m_mutex);
    if (m_sentinels.contains(sentinel)) return false;
    m_sentinels.insert(sentinel);
    return true;
  }

public:
  explicit Sentinel(const char * sentinel) :
    m_sentinel(sentinel), m_ok(checkAndSet(m_sentinel)) {}
  ~Sentinel() { 
    if (!m_ok) return;
    QMutexLocker lock(&m_mutex);
    m_sentinels.remove(m_sentinel);
  }
  bool operator()() const { return m_ok; }
};
QMutex Sentinel::m_mutex;
QSet<QString> Sentinel::m_sentinels;

...
void Foo::m_lineEdit1Changed()
{
  Sentinel s(SENTINEL_AT);
  if (!s) return; // exit if this method is on the call stack
  ...
  changedata1();
  emit someSignal();
}

这是线程安全的,可以在任何线程中使用。