Funktionen aus Thread starten (QtWidget Methode)

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Tinker232
User
Beiträge: 50
Registriert: Mittwoch 25. Juli 2018, 13:45

Hallo zusammen,

ich möchte gerne eine Methode starten, die optische Merkmale auf meiner grafischen Oberfläche setzt, wie z.B. Progress_Bar.setValue(0)

Hintergrund ist:
Ich habe einen Thread der Daten schreibt. Während dieser Zeit sind diverse Elemente auf meinem GUI gesperrt, wie z.B. ein Slider.
Drücke ich nun den Stop_Button wird innerhalb des Threads die Schleife beendet und die restlichen Daten werden geschrieben, bis meine Queue leer ist.
Erst dann sollen die Elemente auf dem GUI wieder freigegeben werden bzw. die Progress_Bar auf 0 gesetzt werden.
Um meine Elemente erst dann freizugeben wenn der Thread auch beendet ist, wollte ich die Funktion "setze_style_gui" direkt aus dem Thread starten, bevor er sich beendet. Also als letzte Amtshandlung des Threads sozusagen.
Praktisch gesehen funktioniert das auch in den meisten Fällen, jedoch habe ich gelesen, dass Veränderungen von QWidgets aus einem Thread nicht threadsafe sind und massive Probleme verursachen können.
Nach etlichen Versuchen hatte ich dann auch einen kompletten Absturz mit der Meldung:

Code: Alles auswählen

QWidget::repaint: Recursive repaint detected.
Jetzt ist meine Frage...
Wie kann ich aus meinem Thread die Funktion "setze_style_gui" starten, die sich in meinem Mainloop (GUI) befindet. Die Funktion enthält Methoden von QWidgets!

Code: Alles auswählen

def setze_style_gui(self, is_standby):
self.is_standby = is_standby
if self.is_standby:
   self.label_1.setText...
   self.label_2.setStyleSheet ...
   self.schieber.setEnable(True)
   self.Progress_Bar.setValue(0)
else:
   self.label_1.setText...
   self.label_2.setStyleSheet ...
   self.schieber.setDisabled(True)
   
   # Thread #
... Schleife zum Schreiben der Daten...
... Wenn Queue leer ist dann, Schleife abbrechen..
   self.setze_style_standby(True)
Kann ich das mit Signalen & Slots irgendwie abbilden? Ich habe ja hier kein Widget was das Signal sendet wie einen Button oder ähnliches?
Danke LG Tina
Benutzeravatar
__blackjack__
User
Beiträge: 14033
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tinker232: Signale kann jedes QObject senden, das muss kein Widget sein. Du kannst also auch in einem von QObject abgeleiteten Objekt ein Signal definieren das Du dann sendest wenn zum Beispiel die Aufgabe zuende abgearbeitet ist.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Tinker232
User
Beiträge: 50
Registriert: Mittwoch 25. Juli 2018, 13:45

Das bedeutet jedoch, dass ich zuvor ein QObject erzeugen müsste. Ich habe in dem Thread kein QObject welches mein Signal emitten könnte, oder?
Benutzeravatar
__blackjack__
User
Beiträge: 14033
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tinker232: Da ich den Code nicht kenne weiss ich nicht ob Du so ein Objekt hast, aber man würde sich ja auch eher speziell dafür ein eigenes Signal definieren. Wobei `QThread` vielleicht einen Blick wert ist. An der Stelle ist dann immer die Frage wie weit man die Programmlogik von Qt abhängig machen möchte, oder ob das grundsätzlich Teile sind, die auch ohne Qt laufen können sollen. Im letzteren Fall könnte man auch eine Rückruffunktion in den eigenen Code einbauen und über die dann die Verbindung zu Qt-spezifischem Code schlagen, also beispielsweise mit einer von QObject abgeleitete Klasse mit einem Signal. Wobei man da eventuell auch schon eine passende Klasse hat, die man nur durch eine Signaldefinition erweitern muss.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du solltest QThread verwenden. Denn dadurch erst kann das senden von Signalen thread-sicher erfolgen. Dazu prueft Qt, ob der Sender eines Signals dem gleichen Thread wie der Empfaenger. Wenn dem nicht so ist, dann benutzt es sogenannte "Queued Connections", die in den mainloop des Empfaengerthreads eingetuetet werden, und da dann sicher ihre Wirkung entfalten koennen.

Und ein QObject einzufuehren ist ja nun nur wenige Zeilen Code. Ggf. kommst du dank pyqt da aber auch drumrum, denn Phil hat ja Unterstuetzung fuer alleinstehende Funktionen, lambdas etc eingebaut.

Nachtrag: wenn du deinen Thread einen QThread machst, dann *hast* du ein QObject. Normalerweise macht man aber noch ein explizites worker-Object.
Tinker232
User
Beiträge: 50
Registriert: Mittwoch 25. Juli 2018, 13:45

Hallo zusammen, danke für die Hinweise...
Ich habe es nun mittels eigenem Signal / Slot erledigt -> http://zetcode.com/gui/pyqt5/eventssignals/
Funktioniert Prima so!
Danke nochmal
LG
Antworten