PyQt: Verbindet ein signal an einen slot zum starten einer hintergrund-Betrieb
Ich habe den folgenden code ausführt, hintergrund Betrieb (scan_value
) beim Update der Fortschrittsbalken in der Benutzeroberfläche (progress
). scan_value
durchläuft einen gewissen Wert obj
, das ein signal ausstrahlt (value_changed
) jedes mal, wenn der Wert geändert wird. Aus Gründen, die hier nicht relevant, ich muss wickeln Sie diese in ein Objekt (Scanner
) in einem anderen thread. Der Scanner wird aufgerufen, wenn Sie die a-Taste scan
ist clicked
. Und hier kommt meine Frage ... der folgende code funktioniert einwandfrei (d.h. die Fortschrittsanzeige aktualisiert wird).
# I am copying only the relevant code here.
def update_progress_bar(new, old):
fraction = (new - start) / (stop - start)
progress.setValue(fraction * 100)
obj.value_changed.connect(update_progress_bar)
class Scanner(QObject):
def scan(self):
scan_value(start, stop, step)
progress.setValue(100)
thread = QThread()
scanner = Scanner()
scanner.moveToThread(thread)
thread.start()
scan.clicked.connect(scanner.scan)
Aber wenn ich den letzten Teil:
thread = QThread()
scanner = Scanner()
scan.clicked.connect(scanner.scan) # This was at the end!
scanner.moveToThread(thread)
thread.start()
Die Fortschrittsanzeige aktualisiert wird nur am Ende (meine Vermutung ist, dass alles auf dem gleichen thread). Sollte es irrelevant sein, wenn ich schließen Sie das signal an einen slot vor oder nach dem Umzug das Objekt erhalten Objekt auf den Thread.
progress.setValue(100)
thread unsichere, weil Sie Zugriff auf eine Qt-GUI-Objekt aus einem anderen thread als dem Hauptthread. Der rest deines geposteten code threadsicher ist in Bezug auf die Qt-GUI-OperationenEs wäre interessant zu wissen, ob es eine PyQt Fehler hier, oder wenn es ist gerade eine Besonderheit, wie PyQt Verbindung zu Python callables. Ich weiß, dass irgendeine Art von proxy-Objekt wird erstellt, wenn
@pyqtSlot
nicht verwendet, aber genau das, was Konsequenzen hat für die verbindungen in der Warteschlange, weiß ich nicht.Ich denke, es könnte eine PyQt4-bug, oder zumindest ein Mangel, der korrigiert werden sollte. Es ist sicherlich nicht zeigen das gleiche Verhalten in PySide (PySide läuft immer die
scan
Funktion in der QThread-unabhängig davon, wo das signal war conected oder wie der slot ist eingerichtet). Ich habe eine minimilistic Beispiel hier pastebin.com/SqP3WM1z , Drucke, von welchem thread die Dinge laufen werden.Danke für den test-Fall. Ich glaube, ich habe festgestellt, warum das problem Auftritt (siehe meine aktualisierte Antwort). Angesichts der Art und Weise PyQt funktioniert derzeit, ich glaube, ich würde jetzt sagen, dass es ist ein Mangel und nicht ein bug. Nicht sicher, ob es möglich wäre, es zu korrigieren, aber.
InformationsquelleAutor Hernan | 2013-12-23
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sollte es keine Rolle, ob die Verbindung vor oder nach dem verschieben des worker-Objekts auf den anderen thread. Zitat aus der Qt-Doku:
So, solange die
type
argumentconnect
eingestellt istQtCore.Qt.AutoConnection
(das ist der Standard), Qt sollte sicherstellen, dass die Signale, die emittiert werden, in der geeignete Weg.Das problem mit dem Beispiel-code ist eher mit der slot als die signal. Die python-Methode, die das signal angeschlossen ist, muss wahrscheinlich so markiert werden, dass eine Qt-slot, mit pyqtSlot Dekorateur:
BEARBEITEN:
Es sollte klargestellt werden, dass es nur in relativ aktuellen Versionen von Qt, dass die Art der Verbindung wird bestimmt, wenn das signal emittiert wird. Dieses Verhalten wurde eingeführt (zusammen mit einigen anderen änderungen in Qt multithreading unterstützt) mit der version 4.4.
Auch, es könnte sich lohnen, weiter zu expandieren auf der PyQt-Problem. In PyQt, ein signal angeschlossen werden kann zu einer Qt-slot, ein anderes signal, oder python aufrufbar. Für letzteren Falle ein proxy-Objekt erstellt, intern, wickelt sich der python aufrufbar und bietet den slot, der erforderlich ist, durch die das Qt signal/slot-Mechanismus.
Es ist das proxy-Objekt, das die Ursache des Problems. Sobald der proxy erstellt wird, PyQt einfach, dies zu tun:
ausreichend ist, wenn die Verbindung hergestellt ist nach das empfangende Objekt wurde verschoben, um seinen thread; aber wenn es gemacht vor, der proxy Aufenthalt in der Haupt-thread.
Mithilfe der
@pyqtSlot
Dekorateur, vermeidet dieses Problem insgesamt, denn es schafft eine Qt-slot mehr direkt und nicht über einen proxy-Objektes.Schließlich sollte auch angemerkt werden, dass dieses Problem derzeit nicht beeinflussen PySide.
InformationsquelleAutor ekhumoro
Mein problem wurde gelöst, indem movinf die Verbindung zu der Stelle, wo der worker-thread initialisiert wird, in meinem Fall, da ich Zugriff auf ein Objekt, das existiert nur nach der Instanziierung von meiner Worker-Objekt-Klasse, die in einem anderen thread.
Verbinden Sie einfach das signal nach der
self.createWorkerThread()
Hinsichtlich
InformationsquelleAutor Josep Jesus Bigorra Algaba
Dies hat zu tun mit der Verbindung Typen von Qt.
http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html#connect
http://qt-project.org/doc/qt-4.8/qt.html#ConnectionType-enum
Bei beiden Objekten im gleichen thread, ein standard-Anschluss-Typ gebildet ist, die Ergebnisse in einem einfachen Aufruf der Funktion. In diesem Fall entfällt die zeitaufwändige operation erfolgt in der GUI thread und die Schnittstelle blockiert.
Im Fall der Anschluss-Typ ist ein message-passing-style-Anschluss, der das signal emittiert wird, mit einer Nachricht, die verarbeitet wird, in dem anderen thread. Der GUI-thread ist jetzt frei, um die Benutzeroberfläche aktualisieren.
Wenn Sie nicht geben Sie den Verbindungstyp in der connect-Funktion, der Typ wird automatisch erkannt.
InformationsquelleAutor Windel