Seite 1 von 1

Signal<->Slot zwischen Thread und Hauptwidget

Verfasst: 20. Januar 2010 11:37
von Mandel
Hallo zusammen ...

Ich versuche mich gerade in Qt einzuarbeiten, da ich demnächst ein Programm mit grafischer Benutzeroberfläche konstruieren muss. Zur Zeit beschäftige ich mich gerade mit Threads, da auch das Programm später mal eine (Endlos)Schleife besitzen wird, welche Daten verarbeitet.

Ich bin nun auf ein Problem gestoßen, welches ich nicht lösen kann.
Mir ist es möglich, aus dem Thread heraus ein Signal zu sende, auf welches ein Slot im Hauptwidget reagiert, umgekehrt geht es allerdings anscheinend nicht...

Hier mal der Konstruktor des Threads:

Code: Alles auswählen

MyThread::MyThread(QObject *parent)
: QThread(parent)
{
	connect(this, SIGNAL(ThreadSignal(int)), parent, SLOT(talk(int)));
	connect(parent, SIGNAL(customSignal2()), this, SLOT(RePos()));
}
Im Widget aus dem der Thread aufgerufen wird (wenn ich das recht verstehe also das parent QObject) befindet sich der Slot "talk(int)". Dieser wird auch aufgerufen, wenn im Thread "Threadsignal" aufgerufen wird.
Im Thread existiert nun der Slot "RePos()", welcher aufgerufen werden soll, wenn im Widget das Signal "customSignal2()" gesendet wird.
Dies geschieht allerdings nicht.
Wenn ich das Programm starte erscheint im Konsolenfenster auch immer folgende Meldung:
"Object::connect: No such slot MyThread::RePos() in c:\...\mythread.cpp:11
Object::connect: (sender name: 'myQtAppDLG')"

In Zeile 11 steht der besagte connect-Befehl im Konstruktor. Ich bin mir nicht sicher, aber wenn ich das richtig Verstehe, ist myQtAppDLG die Klasse, welche vom Designer erstellt wird, wenn ich die Benutzeroberfläche erstelle, oder?

Ich würde mich sehr über euere Hilfe freuen :D

Verfasst: 20. Januar 2010 11:48
von AuE
Warum connectest im Thread und nicht dort wo den Thread erstellst?

zB so:

Code: Alles auswählen

MyThread *thread = new MyThread(this);
connect (this, SIGNAL(a()), thread(), SLOT(on_a()));

Verfasst: 20. Januar 2010 11:51
von franzf
Zeig mal die Klassen-Definition von MyThread.
Vor allem will ich wissen, wie MyThread::RePos() deklariert ist!
Denn die Warnung auf der Console

Code: Alles auswählen

Object::connect: No such slot MyThread::RePos() in c:\...\mythread.cpp:11 
Ist eigentlich eindeutig...

Verfasst: 20. Januar 2010 13:17
von Mandel
Hier erstmal die Klassendefinition von RePos(). zZ steht da aber noch nicht viel drin. War ja erstmal nur nen Versuch, um zu schauen, ob ichs verstanden hab ;)

Code: Alles auswählen

MyThread::MyThread(QObject *parent)
: QThread(parent)
{
	connect(this, SIGNAL(ThreadSignal(int)), parent, SLOT(talk(int)));
	connect(parent, SIGNAL( customSignal2() ), this, SLOT( RePos() ));
}

void MyThread::run()
{
	int i=0;
	printf("\nMyThread läuft ...\n");
	
	for(i=0;i<10;i++)
	{
		_sleep(1000);
		emit ThreadSignal(i);

	}
	exec();
}

void MyThread::SetPos(int x)
{
	Pos=x;
}

void MyThread::RePos()
{
	printf("Tada\n");
}
@AuE
Also "anders herum" hab ichs auch schon probiert und die gleiche Meldung erhalten...

Verfasst: 20. Januar 2010 13:41
von franzf
Mandel hat geschrieben:Hier erstmal die Klassendefinition von RePos().
Das was du postest ist die Definition der Methoden, ich will aber die der Klasse :D

Code: Alles auswählen

class MyThread : public QThread
{
public:
   /* und so weiter */
};
Ich nehme an dass da was mit der deklaration deines SLOT RePos nicht stimmt, z.B. ein "public slots:" oder so vergessen.

Verfasst: 20. Januar 2010 13:55
von Mandel
:oops:
Das ist jetzt aber peinlich... Nicht nur, dass ich mich verlesen hab...
Auch das ich das "slots" hinter "public" vergessen hab.
Und da saß ich jetzt über nen Tag dran, weil ich gedacht hab, dass durch die Threads irgendwelche Besonderheiten zu beachten sind ...

Jetzt funktionierts, danke :roll:

Verfasst: 21. Januar 2010 19:17
von solarix
Und da saß ich jetzt über nen Tag dran, weil ich gedacht hab, dass durch die Threads irgendwelche Besonderheiten zu beachten sind ...
Bei Threads gibt es verdammt viel zu beachten... nur noch ein kleiner Hinweis:

Code: Alles auswählen

MyThread::MyThread(QObject *parent)
: QThread(parent)
{
   connect(this, SIGNAL(ThreadSignal(int)), parent, SLOT(talk(int)));
   connect(parent, SIGNAL( customSignal2() ), this, SLOT( RePos() ));
} 
So wird der Slot "talk" im Kontext des Threads ausgeführt und "RePos" im Kontext der GUI... das kann durchaus so gewollt sein... muss es aber nicht (siehe zahlreiche andere Threads in diesem Forum).

hth..

Verfasst: 22. Januar 2010 09:27
von Mandel
Vielen Dank für deinen Hinweis!
Das ist nicht gewollt, in dem Fall aber auch nicht störend...

Angenommen, ich wöllte, dass talk(int) im Thread selbst und RePos() im Kontext der GUI ausgeführt wird, was habe ich da für Möglichkeiten?

Naiverweise würde ich erstmal vermuten, dass es in diesem Fall reichen würde connect(..) in die GUI umzulagern, oder?

Allerdings könnte ich mir auch vorstellen, dass es Situationen gibt, wo vielleicht andere Lösungen sinnvoll wären?! Gibt es also noch andere Möglichkeiten? Einem Slot sozusagen bewusst in einem bestimmten hread auszuführen...

Verfasst: 22. Januar 2010 09:39
von AuE
Wenn du Sachen der GUI ändern möchtest geht das nur im GUI thread. Da wäre es sinnvoll!

Verfasst: 24. Januar 2010 16:23
von qqq
Hallo Zusammen,

also ich habe ein ähnliches Anliegen wie Mandel. Ich möchte, dass mein angelegter Thread indirekt Sachen auf dem GUI verändern kann.

Nur leider funktioniert es bei mir nicht...

ich habe mir ganz normal einen eigenen Thread von QThread abgeleitet run() implementiert (was auch alles super klappt)...

wenn ich jetzt im Thread ein Signal Signal1(int) erstelle
-> in der run methode steht "emit Signal1(i)"
-> Signal1(int) steht in thread headerdatei unter signals:
und in der GUI Klasse einen Slot zeichne(int)
-> steht in GUI headerdatei .h unter public slots:
dann funktioniert das aber irgendwie nicht.

Im Konstruktor von meinem Thread steht:
connect(this, SIGNAL(Signal1(int)), parent, SLOT(zeichnen(int a)));

(habe auch probiert in der GUI Klasse nach dem Erstellen des Threads folgendes einzugeben:
connect(threadobjektname, SIGNAL(Signal1(int)), this, SLOT(zeichnen(int)));
)

führt aber alles immer zu der gleichen Fehlermeldung:

Fehler 1 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""protected: void __thiscall test::Signal1(int)" (?Signal1@test@@IAEXH@Z)" in Funktion ""public: virtual void __thiscall test::run(void)" (?run@test@@UAEXXZ)". test.obj power

(test ist meine QThread Klasse)

Was mache ich falsch? :(

Verfasst: 24. Januar 2010 18:49
von Christian81
Q_OBJECT in der test - Klasse auch vorhanden?

Verfasst: 25. Januar 2010 10:55
von qqq
Ja, der Konstruktor der Thread Klasse beinhaltet
(QObject *parent)

Verfasst: 25. Januar 2010 11:05
von franzf
qqq hat geschrieben:Ja, der Konstruktor der Thread Klasse beinhaltet
(QObject *parent)
Das ist nicht gemeint!
Du sollst das Macro "Q_OBJECT" in deine Test-Klasse-Definition legen.
Nix Q_OBJECT, nix SIGNAL/SLOT.

Verfasst: 25. Januar 2010 12:51
von qqq
ahhh :)

Daran lag es... vielen Dank :)