Pyqt5 qthread + Signal funktioniert nicht + gui freeze

8

Ich versuche, einen Postfach-Checker mit imap lib zu erstellen, es funktioniert ziemlich gut mit Python, Queue und Multithread ohne GUI.

Aber wenn ich versuche, ein GUI zu setzen, mache ich jede Funktion, die ich mache, um die GUI einzufrieren, bis ich fertig bin.

Ich habe versucht, viele Dinge aus verschiedenen doc (fügen qthread, Signal, Cursor etcc) und Tutorials keine für mich gearbeitet.

Kann jemand mir helfen zu verstehen, wie man einen Text an einen QtextEdit anlegt oder anfügt, während man eine Funktion ausführt, weil es erst nach dem Ende funktioniert.

Hier ist mein Code:

%Vor%     
kenjii himura 07.01.2017, 21:35
quelle

3 Antworten

23

Da es häufig Fragen zur Verwendung von QThread in PyQt gibt, ähnlich wie bei Ihnen, hier ein Beispiel, das zeigt, wie man Threads in PyQt korrekt verwendet. Ich hoffe, dass es als Antwort für ähnliche Fragen nützlich sein kann, also verbrachte ich etwas mehr Zeit als sonst, um dies vorzubereiten.

Das Beispiel erstellt eine Anzahl von Worker-Objekten, die in Nicht-Haupt-Threads ausgeführt werden und mit dem Hauptthread (dh GUI) über die asynchronen Qt-Signale kommunizieren.

%Vor%

Die wichtigsten Konzepte zum Verständnis der Multi-Thread-Programmierung in PyQt sind die folgenden:

  • Qt-Threads haben ihre eigene Ereignisschleife (spezifisch für jeden Thread). Der Hauptthread, auch GUI-Thread genannt, ist ebenfalls ein QThread , und seine Ereignisschleife wird von diesem Thread verwaltet.
  • Signale zwischen Threads werden (asynchron) über die Ereignisschleife des empfangenden Threads übertragen. Daher Reaktionsfähigkeit der GUI oder eines Threads = Fähigkeit, Ereignisse zu verarbeiten. Wenn z. B. ein Thread in einer Funktionsschleife beschäftigt ist, kann er keine Ereignisse verarbeiten, so dass er nicht auf Signale von der GUI reagiert, bis die Funktion zurückkehrt.
  • Wenn ein Worker-Objekt (Methode) in einem Thread seinen Aktionsablauf aufgrund von Signalen von der GUI ändern muss (zB um eine Schleife oder eine Wartezeit zu unterbrechen), muss% code% auf processEvents() aufgerufen werden. Beispiel. Dies ermöglicht QThread, Ereignisse zu verarbeiten und Slots als Antwort auf asynchrone Signale von der GUI aufzurufen. Beachten Sie, dass QApplication scheinbar QApplication.instance().processEvents() für jeden Thread aufruft. Wenn dies nicht erwünscht ist, ist processEvents() eine gültige Alternative.
  • Ein Aufruf von QThread.currentThread().processEvents() beendet die Ereignisschleife nicht sofort: Sie muss auf den aktuell ausgeführten Slot (falls vorhanden) warten, um zurückzukehren. Wenn also ein Thread zum Beenden aufgefordert wird, müssen Sie darauf warten (). Um einen Worker-Thread abzubrechen, muss er normalerweise (über ein benutzerdefiniertes Signal) signalisiert werden, was auch immer er gerade tut: Dies erfordert ein benutzerdefiniertes Signal auf einem GUI-Objekt, eine Verbindung dieses Signals mit einem Worker-Slot und die Worker-Arbeitsmethode muss Thread% aufrufen. co_de%, damit das ausgesendete Signal während der Arbeit den Steckplatz erreichen kann.
Oliver 12.01.2017, 05:43
quelle
1

Ich kann nicht testen, weil settimap auf meinem System nicht verfügbar ist. Ich habe CheckerThread in Checker umbenannt, da es kein Thread mehr ist (es "lebt" nur in einem Thread):

%Vor%

Dann ersetzen Sie einfach den Inhalt der Schleife in gogogo(self) mit diesem:

%Vor%

Es ist fast immer eine gute Idee, Slots mit pyqtSlot zu dekorieren, also sollten sowohl run als auch checkedok so dekoriert werden.

Die SO Antwort über Qt-Threads ist ziemlich praktisch, um sich an Details zu erinnern (beachten Sie jedoch dass es Verbindungen im alten Stil verwendet - Sie müssen C ++ connect( sender, SIGNAL(sig), receiver, SLOT(slot)); in PyQt5 sender.sig.connect(receiver.slot) übersetzen.

    
Oliver 09.01.2017 20:28
quelle
0

Sorry für die späte Antwort, aber es ist eine Technik, die ähnliche Probleme lösen kann.

Das Problem ist klar. Die GUI friert ein, weil ihr Thread einen anderen Job ausführen muss. Eine abstrahierte (vom PyQt-Punkt) Lösung ist unten angegeben:

  1. Erstellen Sie eine Klasse, die von threading.Thread erbt, das der Worker ist.
  2. Übergeben Sie dem Konstruktor eine Warteschlange (queue.Queue) als Kommunikationsmittel.
  3. Sie können den Worker-Thread über den GUI-Thread starten und Nachrichten mithilfe der Warteschlange übergeben.
  4. Damit der GUI-Thread die Nachrichten liest, erstellen Sie einen QTimer mit einem Intervall Ihrer Wahl und registrieren Sie eine Callback-Funktion. In der Callback-Funktion lesen Sie die Warteschlange.

Beispielcode:

%Vor%

self.timer.timeout.connect registriert die Callback-Funktion.

    
Vaggos Phl 18.09.2017 12:31
quelle