Multithread Beispiel korrekt?

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Dragonfire
User
Beiträge: 22
Registriert: Dienstag 28. Februar 2012, 09:03

Hallo Community,
seit kurzen habe ich mich in pythonQt eingearbeitet ...
Nun stehe ich vor folgendem Problem:

Im Hintergrund soll etwas geladen und dann angezeigt werden.
In der Zwischenzeit soll die GUI natürlich nicht einfrieren und eventuell eine Animation,
z.b. ein gif Bild zu sehen sein.

Gehe ich richtig in der Annahme, das der optimale Weg ist,
sich eine eigene Thread Klasse zu definieren, welche von QThread erbt (http://www.mail-archive.com/pyqt@riverb ... 16052.html).
Ein Threadobjekt ein Datenfeld der GUI-Klasse zuweisen, welcher dann z.B. über ein Button gestartet wird.
Sobald der Thread fertig ist, sendet er ein selbst definiertes Signal,
welches dann eine Methode in der GUI aufruft, um alle Informationen aus dem lokal gespeicherten Threadobjekt sich zu holen und anzuzeigen.

Kurz ein wenig Code:

Code: Alles auswählen

class GetIssueDateThread(QtCore.QThread):
    mytex = 'n/a'
        
    def __init__(self, parent = None):
        QtCore.QThread.__init__(self, parent)
        
    def run(self):   
        # hier wird etwas gemacht was lange dauert ....
        self.mytex = 42
        self.emit(QtCore.SIGNAL("mySlot()"))
                  
    def __del__(self):
        self.exiting = True
        self.wait()
		
class STXCreator(QtGui.QMainWindow):
    
    def setMyDate(self):
        self.MyTextField.setText(str(self.thread.mytex))
		self.BtnEnter.setEnabled(True)
             
    def __init__(self, parent=None):

        self.thread = GetIssueDateThread()
        self.connect(self.thread, QtCore.SIGNAL("mySlot()"), self.setMyDate)
        
    @QtCore.pyqtSlot()
    def on_BtnEnter_clicked(self):
		self.BtnEnter.setEnabled(False)
        self.thread.start()
Gibt es noch einen anderen Weg?
lunar

@Dragonfire: Das ist schon richtig so, einen anderen, besseren Weg gibt es nicht.

Die Deklaration von "mytex" auf Klassenebene ist allerdings ungewöhnlich, und lässt vermuten, dass Du den Unterschied zwischen Klassen- und Exemplarvariablen in Python noch nicht ganz verstanden hast (Tipp: Der Name sollte in "__init__()" deklariert werden). Und "__del__()" solltest Du unbedingt vermeiden, siehe dazu die Warnungen in der Python-Dokumentation. Welchem Zweck das in diesem Beispiel dienen soll, verstehe ich ohnehin nicht ganz.

Ansonsten gibt es eine modernere Syntax für Signale und Slots, die Du unbedingt verwenden solltest, da sie weniger fehleranfällig ist als die Syntax, die Du verwendest. Näheres dazu ist in der PyQt Referenzdokumentation unter dem Punkt "New style signal and slot support" zu finden.

Ein ausführliches Beispiel zur Verwendung dieser Syntax in Verbindung mit Threads findest Du unter https://github.com/lunaryorn/snippets/b ... rogress.py.
Dragonfire
User
Beiträge: 22
Registriert: Dienstag 28. Februar 2012, 09:03

lunar hat geschrieben: Und "__del__()" solltest Du unbedingt vermeiden, siehe dazu die Warnungen in der Python-Dokumentation. Welchem Zweck das in diesem Beispiel dienen soll, verstehe ich ohnehin nicht ganz.
Da ist natürlich viel Zeugs weggelassen ...
Meine Grundlage beruhte hierauf:

http://diotavelli.net/PyQtWiki/Threadin ... _and_Slots

lunar hat geschrieben:Klassen- und Exemplarvariablen
Man lernt immer wieder neue Wörter ;)
Das kommt davon, wenn man aus einer typisierten Sprache kommt und Objektvariablen erst deklarieren muss,
Für das Beispiel egal, da ich von dem Thread sowieso nur eine Instanz habe,
wenn nicht hätte man sicherlich einige unerwartete Effekte xD
lunar hat geschrieben: Ein ausführliches Beispiel zur Verwendung dieser Syntax in Verbindung mit Threads findest Du unter https://github.com/lunaryorn/snippets/b ... rogress.py.
Genau sowas habe ich gesucht :D *DANKE*
Werde das morgen mal umbauen und hier nochmal posten^^
lunar

@Dragonfire: Dass es in diesem Beispiel egal ist, sehe ich auch... mein Hinweis war allgemeiner Natur. Gewöhne Dir die Verwendung von Klassenvariablen gar nicht erst an, und falls Du mit "typisierten Sprachen" "Java" oder "C#" meinst (Python ist auch typisiert), dann vergiss am besten auch erstmal alles, was Du in diesen Sprachen übers Programmieren gelernt hast. Python unterscheidet sich sehr stark von Java.

Das verlinkte PyQtWiki ist keine so gute Quelle, da steht auch viel Müll drin, und da nur wenige Leute dieses Wiki aktiv ändern, bleiben viele schlechte Beispiele erhalten.
Dragonfire
User
Beiträge: 22
Registriert: Dienstag 28. Februar 2012, 09:03

lunar hat geschrieben:@Dragonfire: Dass es in diesem Beispiel egal ist, sehe ich auch... mein Hinweis war allgemeiner Natur. Gewöhne Dir die Verwendung von Klassenvariablen gar nicht erst an, und falls Du mit "typisierten Sprachen" "Java" oder "C#" meinst (Python ist auch typisiert), dann vergiss am besten auch erstmal alles, was Du in diesen Sprachen übers Programmieren gelernt hast. Python unterscheidet sich sehr stark von Java.
Ich finde so stark unterscheidet python sich nicht von Java ...
Ist aber immer eine Sache, wie man "stark unterscheiden" definiert.

Wenn du noch irgendwelche Quellen mit guten und vor allem aktuellen Beispielen zu PyQt hast würde ich sie mir gerne mal anschauen ...
Im Github Repo habe ich schon ein paar nützlich Snippets gefunden.

Vielen Dank schonmal :D

###

Nachtrag:

Sollte das dann korrekt so sein?

Code: Alles auswählen

class GetIssueDateThread(QtCore.QThread):     
	 progress = pyqtSignal(str)
   
    def __init__(self, parent = None):
        QtCore.QThread.__init__(self, parent)
        
    def run(self):   
        # hier wird etwas gemacht was lange dauert ....
        self.mytex = 42
        self.progress.emit(str(self.mytex))
      
class STXCreator(QtGui.QMainWindow):
    
    def setMyData(self, myStr):
        self.MyTextField.setText(str(self.thread.mytex))
        self.BtnEnter.setEnabled(True)
             
    def __init__(self, parent=None):

        self.thread = GetIssueDateThread()
        self.thread.progress.connect(lambda v: self.setMyData(v))
        
    @QtCore.pyqtSlot()
    def on_BtnEnter_clicked(self):
        self.BtnEnter.setEnabled(False)
        self.thread.start()
Antworten