3

次の状況を考慮してください。

class Foo : public QObject {
  Q_OBJECT
  public:
    void set_A(int a) { emit updated(this); } 
    void set_B(int b) { emit updated(this); }
  signals: 
    void updated(Foo*);
}

Foo f;
connect(&f, SIGNAL(updated(Foo*)), something, SLOT(do_something_heavy(Foo*)), Qt::QueuedConnection)

void bar() { 
  f.set_A(5); f.set_B(6);
}

信号の 1 つだけが通話に到達するようにするにはどうすればよいdo_something_heavy()ですか?

set_A()を使用して呼び出すことができるようにしたいのですdo_something_heavy()が、set_A と set_B の両方が呼び出される場合、2 回はしたくありませんdo_something_heavy()

その特定の送信者/受信者のペアの残りの未処理の信号をすべてアンキューできますか? できれemitば受信時ではなく で、しかしそれは簡潔さとカプセル化のupdated(Foo*)ためです。更新が 2 回発生します。

4

3 に答える 3

2

このシナリオでは、3 つの異なるオプションを考えることができます。すべてのオプションは、シグナルが 1 回だけ送信されることを保証するため、接続をキューに入れる必要はありません。

オプション 1: flush()メソッドのようなものを定義する

その後、flush メソッドは更新されたシグナルを発行しますが、setter メソッドは発行しません。クライアント コードは手動で flush() を呼び出す必要があります。

オプション 2: プログラムがアイドル状態になったときにシグナルを発する

これは、遅延更新が問題ない場合のみの解決策です。これは、アプリケーションがアイドル状態になったときにのみ、シグナルが送信されることを意味します。ただし、キュー接続を使用しているため、これはすでに当てはまります。

これは非常に動的であり、2 つのパラメーターを複数回変更する可能性があり、高価な更新操作は 1 回だけ呼び出されます。

これを実現するには、セッター メソッドでプライベート ブール変数changedを true に設定し、クラス Foo の特別なスロット (スロットとしましょう) に対してシングル ショット タイマー (タイムアウトなし) を開始するだけemitUpdated()です。シングル ショット タイマーは、setter メソッドが呼び出されたのと同じ頻度でスロットを呼び出すため、スロットはこれを気にする必要があることに注意してください。changedtrueかどうかを単純にチェックし、実際のシグナルを発行し、変更を false に設定します。したがって、信号は一度だけ発行されます。

これはすでにキューに入れられていることに注意してください。シングル ショット タイマーはイベント キューに入れられ (複数回)、emitUpdated を呼び出して実際のシグナルを 1 回送信します。したがって、このシグナルに直接接続して、キュー接続に伴う二重のペナルティを回避することをお勧めします。

オプション 3: セッターがすべてのクライアント コードから同じ順序で呼び出されると想定する

これにより、最高のパフォーマンスが得られます。常に を呼び出してから を呼び出しsetA、 でsetBのみ信号を発信するようにしてくださいsetB。リリース コードのオプション (この「プロトコル」を検証するいくつかのアサートを作成する) と、常に両方のメソッドを呼び出したい場合のみ。

于 2012-10-09T19:34:42.700 に答える
0

できることは、do something_heavy() でスロットを切断することです。

つまり、do something_heavy の実行を開始するときに、スロットを切断します。実行が完了したら、スロットを再接続します。このようにして、実行が進行している間、それ以上のシグナルは処理されません。シグナルは送信されますが、対応するスロットが接続されていないため、再度実行されることはありません。

于 2012-10-09T16:20:44.663 に答える