Qtのスロット関数が複数回実行されてしまう問題の原因と解決策

この問題を解決するには 3 つの方法があります。

1. 初期化関数でのみ接続する

初期化関数はプログラム全体で 1 回だけ実行されるため、ここで信号とスロットを接続すると、繰り返し発生する接続の問題を回避できます。

2. スロット機能がトリガーされた後、スロット機能で切断します (この方法は動的接続を実現できます)


 QMetaObject::Connection connectHandler = connect(pBtn, &QAbstractButton::clicked, this, &QtWidgetsApplication2::btnClicked); //
 
最初の
接続を切断します cancel(connectHandler); 
 
// 再接続
connect(pBtn, &QAbstractButton::clicked, this, &QtWidgetsApplication2 ::btnClicked) );

3. 接続関数にパラメータ Qt::UniqueConnection を記述します


Qt::UniqueConnection の機能は、信号が以前に接続されていない場合は接続して true を返し、以前に接続されていた場合は接続されずに false を返します。たとえば、connect(ui.btn, &QAbstractButton::clicked, this, &QtWidgetsApplication2::btnClicked, Qt::UniqueConnection);

5番目のパラメータを接続します

5 番目のパラメータは次の 5 つです。

1.Qt::AutoConnection : デフォルト値 この値を使用すると、シグナル送信時に接続タイプが決定されます。 Qt::DirectConnection タイプが自動的に使用されます。受信信号と送信信号が同じスレッド内にない場合、Qt::QueuedConnection タイプが自動的に使用されます。

追伸:

QThread *startThread = new QThread();
    //シグナル発行が配置されているスレッドは、スロット関数が配置されているスレッドとは異なります。AutoConnect はキュー接続スロット関数であり、スレッド内では実行されません。送信側のスレッドで実行される直接接続として指定し
    ます
    。

上の例と同様に、Test() はメイン UI のスロット関数です。明らかに、Qthread::started シグナルと Test() は同じスレッドにないため、最終的にキュー接続メソッドが使用され、Test() 関数が使用されます。 Test 関数をスレッドで実行したい場合は、パラメーター 5 を Qt::DirectConnection として指定する必要があります。


2.Qt::DirectConnection : スロット関数はシグナル送信時に直接呼び出されます。スロット関数はシグナル送信者のスレッドで実行されます。スロット関数はシグナルを送信した人のスレッド内にあります。この効果は、信号が送信される場所でスロット関数が直接呼び出されたように見えます。これはマルチスレッド環境ではより危険であり、クロススレッド アクセスで問題が発生するためクラッシュを引き起こす可能性があります。これは同期実行として理解できます。emit ステートメントの後のコードは、すべてのスロット関数が実行された後に実行されます。 。(信号とスロット関数の関係は関数呼び出しに似ており、同期的に実行されます)

3.Qt::QueuedConnection : スロット関数は、コントロールが受信者が配置されているスレッドのイベント ループに戻るときに呼び出されます。スロット関数は、シグナル受信者が配置されているスレッドで実行されます。シグナルを受信した人は誰でも参加します。スロット関数が配置されているスレッド。シグナル送信後、スロット関数はすぐには呼び出されず、受信側の現在の関数が実行されてイベント ループに入るまで呼び出されません。これは一般にマルチスレッド環境で使用されます。これは非同期実行として理解できます。emit ステートメントの後のコードは、スロット関数の実行完了を待たずに、シグナルの送信後すぐに実行されます。(このときシグナルはシグナルキューに詰め込まれます。シグナルとスロット関数の関係はメッセージ通信や非同期実行と同様です)


4.Qt::BlockingQueuedConnection : スロット関数の呼び出しタイミングは Qt::QueuedConnection と同じですが、シグナル送信後、送信側のスレッドはブロックされます。これは、スロット関数の実行が終了するまでの非同期シミュレーション同期と同等です。 。受信者と送信者が同じスレッド内に存在してはなりません。そうしないと、プログラムがデッドロックしてしまいます。これは、複数のスレッド間で同期が必要な場合に必要になる場合があります。


5.Qt::UniqueConnection : このフラグは、ビットごとの OR (|) を介して上記の 4 つと組み合わせて使用​​できます。このフラグが設定されている場合、信号とスロットがすでに接続されている場合、繰り返し接続は失敗します。それは、繰り返しの接続を避けるためです。
 

おすすめ

転載: blog.csdn.net/m0_52467164/article/details/131069560