QPlainTextEdit hängt

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Hi Leute,

ich bastel gerade an einem tool zum neu bespielen eines Minicomputers. Dazu habe ich ein GUI mit Qt geschrieben über welches man den Vorgang starten kann und ein Log ausgegeben wird.
Wenn ich nun das Log in ein QPlainTextEdit ausgebe erscheinen einzelne Textblöcke erst nach einiger Zeit bzw erst wenn der gestartete Vorgang fertig gestellt ist. Das GUI und der Vorgang in dem ich den Minicomputer neu bespiele laufen in unterschiedlichen Threads. Die CPU Auslastung liegt bei ca 5% also kann es nicht durch eine Sperrung seitens der CPU bzw Parallelität kommen.

Nun wieso erscheinen die Blöcke erst nach einiger Zeit? Gibt es dafür eine Lösung?

€dit: Achja ich benutze PySide 1.0 Qt 4.7 und Python 2.7
Zuletzt geändert von JonasR am Freitag 17. Dezember 2010, 13:31, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wie hast Du das mit den Threads denn gelöst? Bist Du den von (Py)Qt empfohlenen Weg gegangen?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Wenn du damit meinst dass ich die QThreads benutze dann nein :D Ich benutze das threading Modul

Code: Alles auswählen

class WORKER(threading.Thread):
    def __init__(self):
        # Initialize threading
        threading.Thread.__init__(self)
Wenn ich QThreads benutze schmiert mir aus welchem Grund auch immer ab -.-'

btw ich habe oben meine Angaben aktualisiert:
€dit: Achja ich benutze PySide 1.0 Qt 4.7 und Python 2.7
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Es mag bei PySide anders sein, aber bei PyQt würde ich sagen, dass darin der Fehler begraben liegt. Da das aber vor allem aber Qt spezifisch sein sollte vermute ich mal extrem stark, dass eben genau das auch das Problem bei PySide sein dürfte. Du solltest mal in der dortigen Doku nach einem "Threading"-HowTo gucken! Dort sollte beschrieben sein, wie man so etwas idiomatisch löst.

lunar hatte mal nach einer Anregung von mir ein gutes Beispiel für PyQt implementiert: http://www.python-forum.de/viewtopic.php?f=11&t=24036

Wie gesagt, Du solltest Dich wegen PySide absichern, ob das dort so oder so ähnlich funzt.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Hehe okay dann werde ich mich da noch einmal einlesen und mich danach melden ;)
Danke schon mal
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Sooo ich habe mich jetzt mal an Lunar's Beispielt gehalten. So stürzt mein Gui nicht ab, aber das Problem mit den verschwindenden Blöcken ist damit nicht gelöst :(

Das Ganze funktioniert übrigens in PySide genauso wie in PyQt ^^
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Kann es sein, dass einfach das Log nur in bestimmten Abschnitten aktualisiert wird? Ohne Code kann man dazu jetzt nichts genaueres sagen. Bastel doch mal ein Minimalbeispiel, ohne Schnickschnack, das nur den kern lauffähig widergibt.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Das werde ich vielleicht erst am Montag machen :P Habe gleich erstmal Wochenende.
Das Log kommt nach und nach über die Serielle Schnittstelle. Und es wird 100% in das QPlainTextEdit geschrieben. Wenn ich die Textzeilen markiere erscheint urplötzlich der Text.

Nochmals danke das du dich mit meinem Problem beschäftigst =)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wie setzt Du denn den Text? Evtl. musst Du da ein spezielles Update-Signal emitten? Durch das "Markieren" könnte das ja gesendet werden und fehlt eben bei deinem Hinzufügen?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Ich hänge es das was aus der Seriellen Schnittstelle kommt einfach hinten ran.

Code: Alles auswählen

QPlainTextEdit.appendPlainText("TEXT")
Und an ein Update habe ich auch schon gedacht. Bewirkt aber vom Gefühl her nichts nach jedem append das Feld zu Updaten.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Tja, im Zweifel weiß lunar da Rat; sobald er den Thread entdeckt hat, wird es Dir sicherlich einen guten Tipp geben können.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
lunar

Ich warte lieber auf den Quelltext, anstatt jetzt wild herumzuraten.

@Hyperion: Ach ja, war "es" ein Versehen, ein Tippfehler, oder Absicht? Ich weiß nicht, aber irgendwie finde ich es komisch, Personen mit "es" zu bezeichnen ;)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

lunar hat geschrieben:Hyperion: Ach ja, war "es" ein Versehen, ein Tippfehler, oder Absicht? Ich weiß nicht, aber irgendwie finde ich es komisch, Personen mit "es" zu bezeichnen ;)
Ooopsi.... großes Sorry!!! Natürlich ein Tippfehler ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Code
Log

Ist ein wenig unsauber der Code aber ich denke er zeigt das die Blöcke erst spät angezeigt werden. Wenn man das .strip() aus line 49 nimmt funktioniert es recht flüssig. Mir ist als würde er erst alles anzeigen wenn man eine Leere Zeile einfügt.

In meinem Original Code wird übrigens aus der Seriellen Schnittstelle ausgelesen nicht aus einer txt.
Und bitte keine Haue wegen dem global :D
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

dein Hauptproblem ist, dass du von einem anderen Thread aus auf den 'textEdit' zugreifst. Dies haben GUIs nicht gerne und reagieren darum auch nicht sauber. PyQt beschwert sich mit folgenden Fehlermeldungen:

Code: Alles auswählen

QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
Deine READTXT-Klasse (nicht PEP8 konform) muss ein Signal senden sobald eine Linie gelesen wurde. Dies macht man mit PyQt so:

Code: Alles auswählen

class ReadTXT(QtCore.QThread):
    new_line_read = QtCore.pyqtSignal(unicode)

    def run(self):
        file = open("log.log", "r")
        lines = file.readlines()
        file.close()

        for line in lines:
            time.sleep(0.1)
            self.new_line_read.emit(line.strip())
Die Datei könnte man mit dem 'with'-Konstrukt auslesen, dann müsste man auch nicht die ganze Datei im speicher halten. Aber da du eh von der seriellen Schnittstelle liest, ist dies hier ja nicht relevant.

Ich habe den connect aufruf in die MainGUI-Klasse verschoben, da gehört er eher hin. Ausserdem sind die globalen Variablen nicht wirklich nötig und stören nur.
Die WORKER-Klasse kannst du auch weglassen.

#edit: ich habe alles mit PyQt gemacht.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

DaMutz hat geschrieben: Deine READTXT-Klasse (nicht PEP8 konform) muss ein Signal senden sobald eine Linie gelesen wurde.
Genau das wurde ja auch so bei den von mir verlinkten Beispielen demonstriert :!:
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

@DaMutz danke erstmal für deine Mühe, ich glaube ich muss mir mal ein ordentliches Tutorial fürs arbeiten mit Qt suchen. Hast du da was zur Hand? Ansich verstehe ich was du meinst bin mir aber mit den Signalen und Slots ein wenig unsicher...

@DaMutz und Hyperion :oops: Habe mir soeben die PEP8 Richtlinien durchgelesen und versuche mich beim nächsten mal dran zuhalten ;)
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

CODE

So ich habe mal ein wenig auf und umgeräumt... Leider habe ich es nicht zum laufen gebracht.

Wieso wird das Signal anscheinend nicht gesendet?
Und wenn ich Zeile 29:

Code: Alles auswählen

read.newLineRead.connect(self.test)
durch

Code: Alles auswählen

read.newLineRead.connect(textEdit.appendPlainText)
ersetze wird dann der text von Zeile 50 automatisch als Eingabevariable gesetzt?


Btw wie bekomme ich Zeile 19 bis 22 auf 80 Zeichen getrimmt? ^^
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

Sieht schon viel besser aus :-)
JonasR hat geschrieben:Wieso wird das Signal anscheinend nicht gesendet?
Das Signal wird schon gesendet, nur machst du kein connect, bzw. erzeugst ein neues ReadTXT Objekt bei dem du das Signal nicht abfängst, und das korrekt verbundene startest du nicht. Binde doch den 'clicked' Event direkt an 'read.start', dann benötigst du auch die 'startWork' Methode nicht...
JonasR hat geschrieben: Und wenn ich Zeile 29:

Code: Alles auswählen

read.newLineRead.connect(self.test)
durch

Code: Alles auswählen

read.newLineRead.connect(textEdit.appendPlainText)
ersetze wird dann der text von Zeile 50 automatisch als Eingabevariable gesetzt?
ja. Deine Testfunktion benötigt noch einen zusätzlichen Parameter für den Text.
JonasR hat geschrieben: Btw wie bekomme ich Zeile 19 bis 22 auf 80 Zeichen getrimmt? ^^
das weiss ich auch nicht. Ich denke es gibt 2 Möglichkeiten. Entweder du benutzt eine Hilfsvariable für den setText Teil oder du formatierst es so:

Code: Alles auswählen

self.pushButton.setText(
            QtGui.QApplication.translate(
                "Form",
                "Start",
                None,
                QtGui.QApplication.UnicodeUTF8
            )
        )
keine Ahnung ob dies so gut ist.
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Was für ein dummer Fehler :D Denn erstmal danke. Ich werde das ganze bei Zeiten mal umbauen und nochmal bescheid geben ob es klappt ;)
Antworten