Genau das wurde ja auch so bei den von mir verlinkten Beispielen demonstriertDaMutz hat geschrieben: Deine READTXT-Klasse (nicht PEP8 konform) muss ein Signal senden sobald eine Linie gelesen wurde.
QPlainTextEdit hängt
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
@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 Habe mir soeben die PEP8 Richtlinien durchgelesen und versuche mich beim nächsten mal dran zuhalten
@DaMutz und Hyperion Habe mir soeben die PEP8 Richtlinien durchgelesen und versuche mich beim nächsten mal dran zuhalten
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:
durch
ersetze wird dann der text von Zeile 50 automatisch als Eingabevariable gesetzt?
Btw wie bekomme ich Zeile 19 bis 22 auf 80 Zeichen getrimmt? ^^
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)
Code: Alles auswählen
read.newLineRead.connect(textEdit.appendPlainText)
Btw wie bekomme ich Zeile 19 bis 22 auf 80 Zeichen getrimmt? ^^
Sieht schon viel besser aus
keine Ahnung ob dies so gut ist.
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:Wieso wird das Signal anscheinend nicht gesendet?
ja. Deine Testfunktion benötigt noch einen zusätzlichen Parameter für den Text.JonasR hat geschrieben: Und wenn ich Zeile 29:durchCode: Alles auswählen
read.newLineRead.connect(self.test)
ersetze wird dann der text von Zeile 50 automatisch als Eingabevariable gesetzt?Code: Alles auswählen
read.newLineRead.connect(textEdit.appendPlainText)
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:JonasR hat geschrieben: Btw wie bekomme ich Zeile 19 bis 22 auf 80 Zeichen getrimmt? ^^
Code: Alles auswählen
self.pushButton.setText(
QtGui.QApplication.translate(
"Form",
"Start",
None,
QtGui.QApplication.UnicodeUTF8
)
)
"ReadTXT.run" implementierst Du besser so:
Und da Du die neue Signal-Slot-API bereits zur Deklaration des Signals nutzt, spricht nichts dagegen, sie auch beim Verbinden zu nutzen, so dass Zeile 31ff. als "pushButton.clicked.connect(read.start)" formuliert werden kann.
Zum Schluss noch der obligatorische Hinweis auf PEP 8 (e.g. "MAINGUI" umbenennen), und darauf, dass "pushButton" und "textEdit" keine sonderlich aussagekräftigen Bezeichner sind.
Code: Alles auswählen
def run(self):
with open("log.log", "r") as stream:
for line in log:
self.newLineRead.emit(line.strip())
Zum Schluss noch der obligatorische Hinweis auf PEP 8 (e.g. "MAINGUI" umbenennen), und darauf, dass "pushButton" und "textEdit" keine sonderlich aussagekräftigen Bezeichner sind.
mir gefällt die Abhängigkeit der 2 Klassen untereinander nicht!
Erzeuge das 'ReadTXT' in der 'main()' und übergib das Objekt dem 'MainGUI' bei der Erzeugung. Die umgekehrt Kopplung ist meiner Meinung nach nicht nötig. 'ReadTXT' muss nichts von einer GUI wissen. Die '__init__'-Methode der 'ReadTXT' Klassen kannst du dann komplett löschen.
Durch diese Trennung wären die 2 Klassen auch besser einzeln testbar.
Erzeuge das 'ReadTXT' in der 'main()' und übergib das Objekt dem 'MainGUI' bei der Erzeugung. Die umgekehrt Kopplung ist meiner Meinung nach nicht nötig. 'ReadTXT' muss nichts von einer GUI wissen. Die '__init__'-Methode der 'ReadTXT' Klassen kannst du dann komplett löschen.
Durch diese Trennung wären die 2 Klassen auch besser einzeln testbar.
"ReadTXT.__init__()" kann man auch so gleich löschen, der Konstruktor tut ja nichts sinnvolles. Aber ich denke, dass ist nur speziell in diesem Beispiel der Fall, tatsächlich wird da wohl irgendeine Art der Initialisierung stehen (e.g. Übergabe des Dateinamens der Logdatei oder so).
Auch sehe ich kein großes Problem in der „Abhängigkeit der Klassen“. Die gibt es gar nicht, denn "ReadTXT" ist auch jetzt schon vollkommen unabhängig von der GUI-Klasse. Allenfalls hängt die GUI-Klasse von ReadTXT ab, aber das ist mit einem einfachen Refactoring zu lösen, und daher meines Erachtens nicht so tragisch. Zumal das im tatsächlichen Quelltext möglicherweise auch so aussehen muss, nämlich wenn ReadTXT erst in Abhängigkeit von gewissen Eingaben in der GUI (e.g. Dateiname der Logdatei aus einem Dateidialog) erzeugt werden kann.
Auch sehe ich kein großes Problem in der „Abhängigkeit der Klassen“. Die gibt es gar nicht, denn "ReadTXT" ist auch jetzt schon vollkommen unabhängig von der GUI-Klasse. Allenfalls hängt die GUI-Klasse von ReadTXT ab, aber das ist mit einem einfachen Refactoring zu lösen, und daher meines Erachtens nicht so tragisch. Zumal das im tatsächlichen Quelltext möglicherweise auch so aussehen muss, nämlich wenn ReadTXT erst in Abhängigkeit von gewissen Eingaben in der GUI (e.g. Dateiname der Logdatei aus einem Dateidialog) erzeugt werden kann.
Bin mir nicht ganz sicher ob "startButton" und "logEdit" sinnvollere Namen sind ^^ aber ich habe die "__init__" Funktion der "ReadTXT" Klasse gelöscht und das "read" Objekt wird nun von der "main" Funktion vererbt.
Habe noch eine Frage bezüglich der Signale.
Wie stelle ich es am besten an das ich die gleichen Signal von mehreren Klassen aus nutzen kann? Wenn ich z.B das Signal "newLineRead" in einer anderen Klasse noch einmal definieren würde müsste ich auch den Slot in der GUI Klasse neu definieren. Würde aber lieber von Zwei Klassen auf einen Slot zugreifen.
Nun habe ich noch eine Frage die sich eher weniger auf diesen Thread richtet:
Wie bringe ich folgenden Beispiel Code auf 80 Zeichen pro Zeile?
Anbei noch der, wie oben beschrieben, veränderte Code.
Habe noch eine Frage bezüglich der Signale.
Wie stelle ich es am besten an das ich die gleichen Signal von mehreren Klassen aus nutzen kann? Wenn ich z.B das Signal "newLineRead" in einer anderen Klasse noch einmal definieren würde müsste ich auch den Slot in der GUI Klasse neu definieren. Würde aber lieber von Zwei Klassen auf einen Slot zugreifen.
Nun habe ich noch eine Frage die sich eher weniger auf diesen Thread richtet:
Wie bringe ich folgenden Beispiel Code auf 80 Zeichen pro Zeile?
Code: Alles auswählen
self.newLineRead.emit("Hallo, ich bin ein mehr als achtzig Zeichen langer Befehl und möchte ohne Zeilenumbruch ausgegeben werden")
Code: Alles auswählen
from PySide import QtCore, QtGui
import sys, time
class MainGui(QtGui.QMainWindow):
def __init__(self, read):
QtGui.QMainWindow.__init__(self)
widget = QtGui.QWidget(self)
widget.setLayout(QtGui.QVBoxLayout(widget))
self.setCentralWidget(widget)
logEdit = QtGui.QPlainTextEdit(widget)
logEdit.setObjectName("textEdit")
widget.layout().addWidget(logEdit)
startButton = QtGui.QPushButton(widget)
startButton.setObjectName("pushButton")
widget.layout().addWidget(startButton)
startButton.setText(
QtGui.QApplication.translate("Form",
"Start",
None,
QtGui.QApplication.UnicodeUTF8
)
)
startButton.clicked.connect(read.start)
read.newLineRead.connect(logEdit.appendPlainText)
class ReadTXT(QtCore.QThread):
newLineRead = QtCore.Signal(unicode)
def run(self):
file = open("log.log", "r")
lines = file.readlines()
file.close()
for line in lines:
self.newLineRead.emit(line.strip())
time.sleep(0.01)
def main():
app = QtGui.QApplication(sys.argv)
read = ReadTXT()
widget = MainGui(read)
widget.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Bitte gewöhne Dir die korrekte Terminologie an. In Deinem Beispiel wird das an "read" gebundene Objekt von "main()" an "MainGUI.__init__()" übergeben, mit Vererbung hat das nicht das Geringste zu tun. Vererbung ist eine Beziehung zwischen Klassen.
Deine Frage bezüglich der Signale verstehe ich nicht, oder anders gesagt, ich kann das beschriebene Problem nicht nachvollziehen. Du kannst doch ganz einfach mehrere, identische oder auch ganz verschiedene Funktionen oder Methoden mit einem Signal verbinden. Wenn Du Methoden zwischen Klassen "teilen" möchtest, in den Sinne, dass beide Klassen diese Methode in identischer Implementierung besitzen, dann hat das nichts mit Signalen und Slots, sondern nur mit den absoluten Grundlagen der Objektorientierung zu tun, die Lösung nämlich heißt Vererbung (und zwar im eigentlichen objektorientierten Sinne, und nicht in dem Sinne, welchem Du diesem Terminus in Deinem Beitrag verpasst hast).
Deine Frage bezüglich der Signale verstehe ich nicht, oder anders gesagt, ich kann das beschriebene Problem nicht nachvollziehen. Du kannst doch ganz einfach mehrere, identische oder auch ganz verschiedene Funktionen oder Methoden mit einem Signal verbinden. Wenn Du Methoden zwischen Klassen "teilen" möchtest, in den Sinne, dass beide Klassen diese Methode in identischer Implementierung besitzen, dann hat das nichts mit Signalen und Slots, sondern nur mit den absoluten Grundlagen der Objektorientierung zu tun, die Lösung nämlich heißt Vererbung (und zwar im eigentlichen objektorientierten Sinne, und nicht in dem Sinne, welchem Du diesem Terminus in Deinem Beitrag verpasst hast).
Sorry wegen der falschen Terminologie.. Werde in Zukunft besser nachdenken bevor ich schreibe
Also ich mochte von Zwei Klassen auf das selbe Signal zugreifen. Ich habe in meinem echten Programm 8 Signale die ich in zwei klassen brauche, das heißt ich muss in der GUI Klasse 16 connect's machen. Ich habe mich nun mal an einem Beispiel mit Vererbung versucht... Das ganze läuft aber nicht wirklich... Klick
Ich habe also eine Talker Klasse erstellt welche das Signal beinhaltet und diese an drei Klassen Vererbt,(Dieses mal ist es sogar richtig ) an meine GUI Klasse und an zwei Klassen die etwas in das Textfeld einfügen sollen. Nun mault der Interpreter aber rum:
Edit: Habe gerade herausgefunden dass ich das "Talker" in den Klassen durch self ersetzen muss Insgesamt wird aber trotzdem nichts in das Textfeld geschrieben. Denke mal dass ich wieder mehrere Signale erstelle und er deswegen nichts empfängt.
Also ich mochte von Zwei Klassen auf das selbe Signal zugreifen. Ich habe in meinem echten Programm 8 Signale die ich in zwei klassen brauche, das heißt ich muss in der GUI Klasse 16 connect's machen. Ich habe mich nun mal an einem Beispiel mit Vererbung versucht... Das ganze läuft aber nicht wirklich... Klick
Ich habe also eine Talker Klasse erstellt welche das Signal beinhaltet und diese an drei Klassen Vererbt,(Dieses mal ist es sogar richtig ) an meine GUI Klasse und an zwei Klassen die etwas in das Textfeld einfügen sollen. Nun mault der Interpreter aber rum:
Denke mal die Talker Klasse wird nicht richtig initialisiert sodass das Signal nicht richtig erstellt wird... Wie geht es richtig?Traceback (most recent call last):
File "C:\scripts\mainExample.py", line 61, in <module>
main()
File "C:\scripts\mainExample.py", line 56, in main
widget = MainGui(read)
File "C:\scripts\mainExample.py", line 34, in __init__
Talker.writeNewLine.connect(logEdit.appendPlainText)
AttributeError: 'PySide.QtCore.Signal' object has no attribute 'connect'
Edit: Habe gerade herausgefunden dass ich das "Talker" in den Klassen durch self ersetzen muss Insgesamt wird aber trotzdem nichts in das Textfeld geschrieben. Denke mal dass ich wieder mehrere Signale erstelle und er deswegen nichts empfängt.
Wie in der Dokumentation beschrieben ist, müssen Klassen, die Signale verwenden, von "QObject" ableiten. Davon abgesehen ist Vererbung wirklich zu viel des Guten, wenn es wirklich nur darum geht, identische Signale in mehreren Klassen zu deklarieren. Da kannst Du die Deklaration auch einfach in jeder Klasse hinzufügen, Vererbung ist nur sinnvoll, wenn wirklich eine signifikante Menge an Quelltext zwischen Klassen zu teilen ist.
Davon abgesehen verstehe ich Dein Problem noch immer nicht. Im vorherigen Beitrag ging es um Slots, die in Python letztlich nichts weiter als normale Methoden sind, jetzt aber geht es Dir auf einmal um Signale, und die sind eben durchaus besondere Attribute.
Im Übrigen ist es eigentlich Grundwissen über Objektorientierung, dass man auf Exemplarattribute mittels "self" zugreift. Das muss Dir klar sein, bevor Du graphische Oberflächen entwickeln möchtest.
Davon abgesehen verstehe ich Dein Problem noch immer nicht. Im vorherigen Beitrag ging es um Slots, die in Python letztlich nichts weiter als normale Methoden sind, jetzt aber geht es Dir auf einmal um Signale, und die sind eben durchaus besondere Attribute.
Im Übrigen ist es eigentlich Grundwissen über Objektorientierung, dass man auf Exemplarattribute mittels "self" zugreift. Das muss Dir klar sein, bevor Du graphische Oberflächen entwickeln möchtest.
Hmm ich werde jetzt einfach in beiden "worker" Klassen die Signale definieren. Ist denke ich einfacher...
Und wie ich self benutze weiß ich natürlich Mir war nur nicht ganz das Ausmaß der Vererbung bewusst. Also was dort geschieht.
Denn mal Danke für die Hilfe =)
Und wie ich self benutze weiß ich natürlich Mir war nur nicht ganz das Ausmaß der Vererbung bewusst. Also was dort geschieht.
Denn mal Danke für die Hilfe =)
@JonasR: Du musst eben den Text des Steuerelements irgendwie an das "Worker"-Exemplar übergeben.
Naja das war mir klar nur blieb ich auch an dem "irgendwie" hängen ^^
Soll ich in dem worker ein Signal senden welches der GUI Klasse sagen soll dass sie das QLineEdit ausliest und in eine var der worker Klasse schreiben soll?
Weiß halt nicht ob es dafür eine gute Lösung gibt...
Soll ich in dem worker ein Signal senden welches der GUI Klasse sagen soll dass sie das QLineEdit ausliest und in eine var der worker Klasse schreiben soll?
Weiß halt nicht ob es dafür eine gute Lösung gibt...
@JonasR: Dann sende doch einfach ein Signal an den Thread, welchem Du den Text des Steuerelements als Parameter mitgibst.