Hi Community,
ich hab mal wieder ein kleines Problem, die Lösung ist wahrscheinlich mal wieder trivial.
Ich starte von meinem GUI Thread einen anderen Thread mit Hilfe von thread.start(). In diesem Thread starte ich nun die Event-Loop mit self.exec_().
Der Thread arbeitet ein Weilchen und emitiert ein Signal welches vom GUI Thread entgegengenommen wird. Der GUI Thread startet eine Benutzterabfrage. Anhand dieser wird entschieden ob thread.search() aufgerufen wird.
Das Problem ist, dass der Aufruf von thread.search() die GUI blockiert. Natürlich könnte ich thread.search() in eine andere Threadklasse auslagern und dann einfach thread.start() aufrufen.
Wie ich das ganze mit Signal und Slot machen würde, wüsste ich nicht auf anhieb, da thread nichts von der GUI wissen soll.
Grüße,
anogayales
Slot eines QThreads aus dem GUi Thread aufrufen
-
- User
- Beiträge: 456
- Registriert: Mittwoch 15. April 2009, 14:11
Zuletzt geändert von anogayales am Freitag 25. Juni 2010, 12:45, insgesamt 1-mal geändert.
-
- User
- Beiträge: 456
- Registriert: Mittwoch 15. April 2009, 14:11
Nachtrag:
Minimalbeispiel:
Minimalbeispiel:
Code: Alles auswählen
from PyQt4 import QtGui
from PyQt4 import QtCore
class Worker(QtCore.QThread):
def __init__(self):
QtCore.QThread.__init__(self)
def run(self):
print "mach was ganz kurzes"
def search(self):
for number in range(20000000):
print number
class Example(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
vbox = QtGui.QVBoxLayout()
self.setLayout(vbox)
vbox.addWidget(QtGui.QTextEdit())
button = QtGui.QPushButton("Work")
vbox.addWidget(button)
self.thread = Worker()
self.thread.start()
self.move(250, 200)
button.clicked.connect(self.thread.search)
app = QtGui.QApplication([])
exm = Example()
exm.show()
app.exec_()
Vllt. so:
Code: Alles auswählen
class Worker(QtCore.QThread):
def __init__(self):
QtCore.QThread.__init__(self)
self.search = False
def run(self):
print "mach was ganz kurzes"
while True:
if self.search:
self.do_search()
time.sleep(0.1)
def do_search(self):
for number in range(20000000):
print number
self.search = False
the more they change the more they stay the same
Wieso lagerst Du die Suche nicht einfach in einen zweiten Thread aus, welchen Du startest, wenn die Abfrage vom Benutzer positiv beschieden wurde?
@anogayales:
Ja die Dokumentation von Qt suggeriert, dass das so funktionieren könnte, dem liegt aber ein entscheidender Denkfehler zugrunde. Bei genauerem Lesen der Dokumentation wird klar, das nur der Code unter run() einen eigenen Threadkontext erhält, d.h. das Threadobjekt selbst "lebt" dort, wo es erzeugt wurde - im Hauptthread. Das gilt für alle Deklarationen ausserhalb von run(). Deshalb blockiert Dein Buttonklick die GUI, die search-Methode wird im Hauptthread ausgeführt.
Der Code unter run() fungiert als main() des neuen Threads, von dort aus kannst Du weitere Objekte erstellen und auch einen eigenen Eventhandler anstossen. Dieser "interne" Eventhandler dient dann dazu, Events von Objekten, die innerhalb von run() erzeugt wurden, zu verwalten bzw. Signale von anderen Threads mit den eigenen threadinternen Events zu sychronisieren (siehe ConnectionType für Signal/Slot-Verbindungen).
Kleines Bsp., um den Threadkontext aufzuzeigen:ergibt:
Hier siehst Du, das MyThread.slotMethod() einmal in MyThread (direkter Aufruf) und einmal im Hauptthread (Signal/Slot) auftaucht. Für den direkten Aufruf ist es klar, hier entscheidet der Caller-Kontext die Threadzugehörigkeit. Für die Signal/Slot-Sache ist es dagegen wichtig zu wissen, in welchem Thread das Objekt "lebt". So zeigt der Aufruf von SubThread.slotMethod via Signal vom Hauptthread auf den Kontext MyThread, da das Objekt SubThread hier erstellt wurde. Ohne Eventhandler in MyThread wird das Signal nicht mehr ausgeliefert und die Methode nicht mehr aufgerufen.
Zurück zu Deinem Problem, die search-Methode muß in irgendeiner Weise mit run() assoziiert sein, entweder durch direkten Aufruf oder durch ein dort erzeugtes Objekt mit der entsprechenden Methode. Einfacher gehts, wie lunar angedeutet hat.
Ja die Dokumentation von Qt suggeriert, dass das so funktionieren könnte, dem liegt aber ein entscheidender Denkfehler zugrunde. Bei genauerem Lesen der Dokumentation wird klar, das nur der Code unter run() einen eigenen Threadkontext erhält, d.h. das Threadobjekt selbst "lebt" dort, wo es erzeugt wurde - im Hauptthread. Das gilt für alle Deklarationen ausserhalb von run(). Deshalb blockiert Dein Buttonklick die GUI, die search-Methode wird im Hauptthread ausgeführt.
Der Code unter run() fungiert als main() des neuen Threads, von dort aus kannst Du weitere Objekte erstellen und auch einen eigenen Eventhandler anstossen. Dieser "interne" Eventhandler dient dann dazu, Events von Objekten, die innerhalb von run() erzeugt wurden, zu verwalten bzw. Signale von anderen Threads mit den eigenen threadinternen Events zu sychronisieren (siehe ConnectionType für Signal/Slot-Verbindungen).
Kleines Bsp., um den Threadkontext aufzuzeigen:
Code: Alles auswählen
from PyQt4 import QtGui, QtCore
class SubThread(QtCore.QThread):
def run(self):
print 'SubThread.run:', self.currentThread()
self.slotMethod()
print 'starte SubThread event loop..'
self.exec_()
print 'stoppe SubThread event loop..'
def slotMethod(self):
print 'SubThread.slotMethod:', self.currentThread()
class MyThread(QtCore.QThread):
def run(self):
print 'MyThread.run:', self.currentThread()
self.slotMethod()
self.subthread = SubThread()
self.subthread.start()
print 'starte MyThread event loop..'
self.exec_()
print 'stoppe MyThread event loop..'
def slotMethod(self):
print 'MyThread.slotMethod:', self.currentThread()
app = QtGui.QApplication([])
print 'Main thread:', app.instance().thread()
thread = MyThread()
thread.start()
QtCore.QTimer.singleShot(200, thread.slotMethod)
QtCore.QTimer.singleShot(200, thread.subthread.slotMethod)
QtCore.QTimer.singleShot(2200, app.quit)
QtCore.QTimer.singleShot(2100, thread.quit)
QtCore.QTimer.singleShot(2000, thread.subthread.quit)
app.exec_()
print "stoppe Main event loop.."
Code: Alles auswählen
Main thread: <PyQt4.QtCore.QThread object at 0x81ae5ac>
MyThread.run: <__main__.MyThread object at 0x81ae5ac>
MyThread.slotMethod: <__main__.MyThread object at 0x81ae5ac>
SubThread.run: <__main__.SubThread object at 0x81ae5ec>
SubThread.slotMethod: <__main__.SubThread object at 0x81ae5ec>
starte MyThread event loop..
starte SubThread event loop..
MyThread.slotMethod: <PyQt4.QtCore.QThread object at 0x81ae62c>
SubThread.slotMethod: <__main__.MyThread object at 0x81ae5ac>
stoppe SubThread event loop..
stoppe MyThread event loop..
stoppe Main event loop..
Zurück zu Deinem Problem, die search-Methode muß in irgendeiner Weise mit run() assoziiert sein, entweder durch direkten Aufruf oder durch ein dort erzeugtes Objekt mit der entsprechenden Methode. Einfacher gehts, wie lunar angedeutet hat.

-
- User
- Beiträge: 456
- Registriert: Mittwoch 15. April 2009, 14:11
Vielen Dank für die ausführliche Klarstellung! Ich hab mich für lunars methode entschieden 
