スロットが呼び出されないという問題がある人々を繰り返し見かけます。最も一般的な理由のいくつかを収集したいと思います。だから私は人々を助け、多くの冗長な質問を避けることができます。
信号/スロット接続が機能しない理由は何ですか?このような問題を回避するにはどうすればよいですか?
信号とスロットの使用を容易にし、接続不良の最も一般的な理由をカバーするいくつかのルールがあります。何か忘れた場合は教えてください。
1)デバッグコンソールの出力を確認します:
実行エラーが発生すると、デバッグ出力に理由が示されます。
2)シグナルとスロットの完全な署名を使用:
の代わりに
_connect(that, SIGNAL(mySignal), this, SLOT(mySlot));
_
書く
_connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
_
スペルと大文字を確認してください。
)既存のオーバーロードを使用:
信号とスロットの目的のオーバーロードを使用しているかどうか、および使用したオーバーロードが実際に存在するかどうかを慎重に確認してください。
4)信号とスロットは互換性がなければなりません:
これは特に、パラメーターが同じタイプ(参照が許容される)であり、同じ順序でなければならないことを意味します。
コンパイル時の構文でも同じ数のパラメーターが必要です。古いランタイム構文では、より少ないパラメーターでスロットに信号を接続できます。
5)常に接続メソッドの戻り値を確認する(プログラマはnever戻り値を無視する必要があります):
の代わりに
_connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
_
常に次のようなものを使用します
_bool success = connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
Q_ASSERT(success);
_
または、例外をスローしたり、完全なエラー処理を実装したい場合。次のようなマクロを使用することもできます。
_#ifndef QT_NO_DEBUG
#define CHECK_TRUE(instruction) Q_ASSERT(instruction)
#else
#define CHECK_TRUE(instruction) (instruction)
#endif
CHECK_TRUE(connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int))));
_
6)キューに入れられた接続にイベントループが必要です:
つまり異なるスレッド(いわゆるキュー接続)が所有する2つのオブジェクトのシグナル/スロットを接続するときは、スロットのスレッドでexec();
を呼び出す必要があります。
イベントループも実際に提供される必要があります。スロットのスレッドがなんらかのビジーループでスタックしているときはいつでも、キューに入れられた接続は実行されません!
7)キュー接続にはカスタムタイプを登録する必要があります:
したがって、キューに入れられた接続でカスタムタイプを使用する場合は、この目的のためにそれらを登録する必要があります。
最初に、次のマクロを使用して型を宣言します。
_Q_DECLARE_METATYPE(MyType)
_
次に、以下のいずれかの呼び出しを使用します。
_qRegisterMetaType<MyTypedefType>("MyTypedefType"); // For typedef defined types
qRegisterMetaType<MyType>(); // For other types
_
8)古いランタイムチェックの構文よりも新しいコンパイル時の構文を優先する:
の代わりに
_connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
_
この構文を使用
_connect(that, &ThatObject::mySignal, this, &ThisObject::mySlot));
_
コンパイル時にシグナルとスロットをチェックし、実際のスロットである宛先を必要としません。
信号が過負荷の場合は、次の構文を使用します。
_connect(that, static_cast<void (ThatObject::*)(int)> &ThatObject::mySignal), this, &ThisObject::mySlot); // <Qt5.7
connect(that, qOverload<int>::of(&ThatObject::mySignal), this, &ThisObject::mySlot); // >=Qt5.7 & C++11
connect(that, qOverload<int>(&ThatObject::mySignal), this, &ThisObject::mySlot); // >=Qt5.7 & C++14
_
また、その構文ではconst/non-constシグナル/スロットを混在させないでください(通常、シグナルとスロットは非constになります)。
9)クラスにはQ_OBJECTマクロが必要です:
「シグナル」と「スロット」の仕様を使用しているクラスでは、次のようなQ_OBJECTマクロを追加する必要があります。
_class SomeClass
{
Q_OBJECT
signals:
void MySignal(int x);
};
class SomeMoreClass
{
Q_OBJECT
public slots:
void MySlot(int x);
};
_
このマクロは、クラスに必要なメタ情報を追加します。
10)オブジェクトは生きている必要があります:
送信者オブジェクトまたは受信者オブジェクトのいずれかが破棄されるとすぐに、Qtは接続を自動的に破棄します。
シグナルが発生しない場合:送信者オブジェクトはまだ存在しますか?スロットが呼び出されない場合:レシーバーオブジェクトはまだ存在しますか?
両方のオブジェクトの存続期間を確認するには、コンストラクター/デストラクターでデバッガーのブレークポイントまたはqDebug()出力を使用します。
11)それでも動作しません:
接続の非常に迅速でダーティなチェックを行うには、いくつかのダミー引数を使用して自分で信号を発信し、それが呼び出されるかどうかを確認します。
_connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int)));
emit that->mySignal(0); // Ugly, don't forget to remove it immediately
_
最後に、もちろん、信号が単に発信されない可能性もあります。上記のルールに従っている場合は、プログラムのロジックに問題がある可能性があります。ドキュメントをお読みください。デバッガーを使用します。そして、他の方法がある場合は、stackoverflowで質問してください。
私の実践では、シグナルを受信するオブジェクトでeventFilterを誤ってオーバーライドするケースに遭遇しました。一部の初心者プログラマーは、関数の最後で「false」を返すのを忘れています。したがって、MetaCallイベントが受信オブジェクトに渡されることを許可しません。この場合、信号は受信オブジェクトで処理されません。
あなたは(ほとんど)もう心配する必要はありません。 connect
のメンバープロトタイプには常にQMetaMethod/Pointerを使用してください。信号とスロットに互換性がない場合、コンパイル時に失敗するためです。
_connect(sourceObject, &SourceClass::signal, destObject, &DestClass::slot);
_
このプロトタイプは、sourceObject
またはdestObject
がnullの場合(予想される)、実行時にのみ失敗します。ただし、コンパイル時に引数の非互換性が表示されます
まれな状況でのみ古いSIGNAL
/SLOT
リテラルベースの構文が必要になるため、これが最後の手段になります。
次の条件を満たす場合、署名は互換性があります。
signalA(int, std::string)
=> signalC(int, std::string)
signalA(int, std::string)
=> slotB(int, std::string)
signalA(int, std::string)
=> slotB(int)
signalA(int, std::string)
=> slotB()
signalA(int, const char*)
=> slotB(int, QString)
QString(const char*)
で変換されますsignalA(int, std::string)
=> slotB(std::string)
int
は暗黙的に_std::string
_に変換できませんsignalA(int, std::string)
=> slotB(std::string, int)
signalA(int, std::string)
=> slotB(int, std::string, int)