web-dev-qa-db-ja.com

Qtで発火信号を防ぐ

QCheckBoxオブジェクトがあります。ユーザーがそれをチェックするか、チェックを解除すると、関数を呼び出してstateChanged ( int state )信号に接続します。一方、条件によっては、コード内のQCheckBoxオブジェクトの状態も変更します。これにより、不要な信号が発生します。

ある条件下で発火信号を防ぐ方法はありますか?

51
metdos

clicked シグナルを使用できます。これは、ユーザーが setChecked

ある特定の時間に信号を発信したくない場合は、 QObject::blockSignals を次のように使用できます。

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

このアプローチの欠点は、all信号がブロックされることです。しかし、QCheckBoxの場合、それは実際には問題ではないと思います。

78
Job

QObject::blockSignals() を使用して、QObjectsでのシグナル発信をいつでもブロックできます。物事を正しくするために、古い状態(関数呼び出しから返される)を覚えて、完了したら復元する必要があることに注意してください。

私の仕事では、この種のことより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:Qt 5.3以降、 QSignalBlocker (コメントでHappyCactusへのh/t)を参照

35

あなたはできる - QObject::disconnect 対応する信号スロット接続を削除し、QObject::connectagain完了したら...

14
liaK

Qtの学習中に、「原子的に」更新したい相互接続されたウィジェットのセットでこの問題に遭遇しました。私は@cjhuittのソリューションが好きでしたが、 プロキシオブジェクト に基づいた少しの構文シュガーでさらに良くなることがわかりました。ここに私が使用したアプローチがあります...

最初に、ブロッカープロキシオブジェクトのクラステンプレートを定義しました。カレブのように、これは建設時の信号をブロックし、破壊時に以前の状態を復元します。ただし、->演算子は、ブロックされたオブジェクトへのポインタを返します。

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; }
};

次に、ブロッカーを作成して返す小さなテンプレート関数を定義しました。

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

これをすべてまとめると、次のように使用します。

whileBlocking(checkBox)->setChecked(true);

または

whileBlocking(xyzzySpin)->setValue(50);

これにより、RAIIのすべての利点が得られます。これは、メソッド呼び出しの前後で自動的にペアになったブロッキングと復元を行いますが、ラッパーまたは状態フラグに名前を付ける必要はありません。それは素晴らしく、簡単で、非常に簡単です。

12
Boojum

QObject派生クラスでは、blockSignals(bool)を呼び出して、オブジェクトが信号を発するのを防ぐことができます。たとえば、次のとおりです。

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

上記のメソッドは、クリック、stateChanged、または他のシグナルが発行されることなくチェック状態を変更します。

6
ZestyMeta

Qt5.3は QSignalBlocker クラスを導入し、例外安全な方法で必要なものを正確に実行します。

if (something) {
   const QSignalBlocker blocker(someQObject);
   // no signals here
}
3
HappyCactus

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, ... 
}
0
peter karasev