2014-10-17 20 views
11

Ich sehe immer wieder Leute, die Probleme mit nicht aufgerufenen Slots haben. Ich möchte einige der häufigsten Gründe sammeln. Vielleicht kann ich Menschen helfen und viele überflüssige Fragen vermeiden.Meine Signal/Slot-Verbindung funktioniert nicht

Aus welchen Gründen funktionieren die Signal-/Steckplatzverbindungen nicht? Wie können solche Probleme vermieden werden?

Antwort

23

Es gibt einige Regeln, die das Leben mit Signalen und Steckplätzen erleichtern und den häufigsten Grund für fehlerhafte Verbindungen abdecken. Wenn ich etwas vergessen habe, sag es mir bitte.

1) Verwenden Sie die volle Unterschrift von Signal- und Slot:

Statt

connect(that, SIGNAL(mySignal), this, SLOT(mySlot)); 

Schreib

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int))); 

und Ihre Rechtschreibung und Kapitalisierung überprüfen.

2) Verwenden bestehende Überlastungen:

carfully überprüfen, ob Sie die gewünschten Überlastungen von Signal- und Schlitz verwenden, und wenn die Überlastung Sie tatsächlich verwendet existieren.

3) Ihr Signal und Schlitz kompatibel sein müssen:

Dies bedeutet insbesondere die Parameter der vom gleichen Typ sein müssen (Referenzen werden toleriert) und haben die gleiche Reihenfolge.

Die Syntax für die Kompilierzeit benötigt ebenfalls die gleiche Anzahl von Parametern. Die alte Runtime-Syntax ermöglicht das Verbinden von Signalen mit Slots mit weniger Parametern.

4) Immer Rückgabewert von connect-Methode überprüfen (Programmierer sollten ignorieren nie Werte zurück):

Statt

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int))); 

immer so etwas wie

bool success = connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int))); 
Q_ASSERT(success); 

verwenden Oder wenn Sie eine Ausnahme auslösen oder eine vollständige Fehlerbehandlung implementieren möchten. Sie können auch ein Makro wie das verwenden:

#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)))); 

5) Sie können eine Ereignisschleife für Verbindungen in Warteschlange müssen:

D.h. Immer, wenn Sie Signale/Slots von zwei Objekten verbinden, die zu verschiedenen Threads gehören (sogenannte Warteschlangenverbindungen), müssen Sie exec(); im Slot-Thread aufrufen!

Die Ereignisschleife muss auch tatsächlich bedient werden. Immer wenn der Thread des Slots in einer Art "busy loop" stecken bleibt, werden in der Warteschlange befindliche Verbindungen NICHT ausgeführt!

6) Sie müssen benutzerdefinierte Typen für Verbindungen in Warteschlange registrieren:

Also, wenn benutzerdefinierte Typen in der Warteschlange Verbindungen verwenden Sie sie für diesen Zweck registrieren.

zunächst die Art mit dem folgende Makro deklariert:

Q_DECLARE_METATYPE(MyType) 

dann eine der folgenden Aufrufe verwenden:

qRegisterMetaType<MyTypedefType>("MyTypedefType"); // For typedef defined types 
qRegisterMetaType<MyType>(); // For other types 

7) Bevorzugen neue Kompilierung Syntax über alte Laufzeit Syntax geprüft :

Statt

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int))); 

Verwendung dieser Syntax

connect(that, &ThatObject::mySignal, this, &ThisObject::mySlot)); 

das Signal und Schlitz während der Kompilierung überprüft und auch nicht das Ziel muss eine tatsächliche Slot zu sein.

Wenn das Signal die folgende Syntax überlastet ist:

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 

auch nicht const/nicht konstante Signale/Slots für diese Syntax (normalerweise Signale und Slots werden nicht konstante) mischen.

8) Ihre Klassen brauchen eine Q_OBJECT Makro:

In Klassen, in denen Sie "Signale" und "Slots" Spezifikationen Sie Q_OBJECT Makro wie folgt hinzufügen müssen verwenden:

class SomeClass 
{ 
    Q_OBJECT 

signals: 
    void MySignal(int x); 
}; 

class SomeMoreClass 
{ 
    Q_OBJECT 

public slots: 
    void MySlot(int x); 
}; 

Dieses Makro fügt der Klasse die erforderlichen Metainformationen hinzu.

9) Ihre Objekte müssen lebendig sein:

Sobald entweder das Senderobjekt oder das Empfängerobjekt zerstört wird, Qt verwirft automatisch die Verbindung.

Wenn das Signal nicht gesendet wird: Ist das Absenderobjekt noch vorhanden? Wenn der Slot nicht aufgerufen wird: Ist das Empfängerobjekt noch vorhanden?

Um die Lebensdauer beider Objekte zu überprüfen, verwenden Sie einen Debugger-Unterbrechungspunkt oder eine qDebug() - Ausgabe in den Konstruktoren/Destruktoren.

10) Es funktioniert immer noch nicht:

eine sehr schnelle und schmutzige Prüfung Ihrer Verbindung zu tun, das Signal von Ihrem Selbst mit einigen Dummy-Argumenten emittieren und sehen, ob es genannt wird:

connect(that, SIGNAL(mySignal(int)), this, SLOT(mySlot(int))); 
emit that->mySignal(0); // Ugly, don't forget to remove it immediately 

Schließlich ist es natürlich möglich, dass das Signal einfach nicht emittiert wird. Wenn Sie die obigen Regeln befolgt haben, liegt wahrscheinlich etwas an der Programmlogik falsch. Lesen Sie die Dokumentation. Verwenden Sie den Debugger.Und wenn es jetzt anders geht, fragen Sie bei stackoverflow.

+0

Sie müssen Ihren benutzerdefinierten Typ nicht wirklich mit 'Q_DECLARE_METATYPE' deklarieren, wenn Sie ihn in einem Warteschlangen-Slot verwenden möchten. 'qRegisterMetatype' sollte ausreichen. 'Q_DECLARE_METATYPE' wird nur für vorlagenbasierte Funktionen benötigt. Es gab eine kurze Diskussion darüber [http://stackoverflow.com/questions/23219770/how-to-register-reference-to-qt-containers/23235165#comment35552191_23235165]. – thuga

+0

Hm. Es scheint, dass QVariant kein direkter Teil des Warteschlangen-Verbindungsmechanismus ist. Die Dokumentation von qRegisterMetaType() besagt jedoch: "Rufen Sie diese Funktion auf, um den Typ T zu registrieren. T muss mit Q_DECLARE_METATYPE() deklariert werden". – Silicomancer