stdout "umlenken" Python3

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
xvzf
User
Beiträge: 13
Registriert: Montag 29. Oktober 2012, 14:14

Hallo,
gibt es eine Möglichkeit die Standartterminal Ausgabe in ein Textwidget
(PyQt4)umzuleiten?
Das ganze in Python3 ;)

Danke :)
BlackJack

@xvzf: Jain. Du kannst `sys.stdout` durch ein eigenes Objekt ersetzen, dass die Ausgaben in ein Textfeld steckt. Aber dadurch wird ein Qt-Textfeld natürlich nicht zu einem vollwertigen Terminal(emulator).
xvzf
User
Beiträge: 13
Registriert: Montag 29. Oktober 2012, 14:14

Nein, das wollte ich auch nicht, dann hätte ich auch stdin müssen umlenken ;)

Kennst du einen Beispielcode ?
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Na, Beispielcode wäre dann wohl `sys.stdout = dein_objekt`, wobei dein Objekt sinnvollerweise eine passende `.write()`-Methode implementieren sollte, wie sie von Code, der in `stdout` schreiben will, erwartet wird. Oder geht es dir in Wirklichkeit vielleicht eher um die Umleitung (Pipe) von Programmausgaben?
xvzf
User
Beiträge: 13
Registriert: Montag 29. Oktober 2012, 14:14

Dann erhalte ich folgende Fehlermeldung:

Code: Alles auswählen

    self.ui.textEdit.setText(sys.stdout)
TypeError: QTextEdit.setText(str): argument 1 has unexpected type '_io.TextIOWrapper'

lunar

@xvzf Das war sicher nicht das, wozu snafu geraten hat. Was bewirkt diese Zeile Deiner Meinung nach? Erwartest Du, dass die Standardausgabe irgendwie automagisch im Textfeld landet?!

Die Fehlermeldung ist ziemlich deutlich… so deutlich, dass Du – wenn Du sie nicht zu interpretieren weißt – besser erst einmal die Finger von GUI-Programmen lässt, weil Dir dann relativ sicher ein paar nötige Grundlagen fehlen. Sie sagt Dir, dass Du ein Dateiobjekt übergibst, wo einfacher Text in Form einer Zeichenkette erwartet wird.

Einem Textfeld kann man nur Text zuweisen. Die Standardausgabe unter sys.stdout ist aber nicht einfach Text, sondern ein Dateiobjekt, in das Text geschrieben wird. Deine Aufgabe ist, sys.stdout ein Dateiobjekt zuzuweisen, dass diese Ausgabe an das Textfeld weiterleitet. Das geschieht nicht automatisch. Dieses Objekt musst Du selbst implementieren, und die Implementierung ist eigentlich relativ trivial.
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hier mal eine mögliche Implementierung:

Code: Alles auswählen

from StringIO import StringIO
import sys

from PyQt4.QtCore import pyqtSignal, QObject
from PyQt4.QtGui import QApplication, QTextEdit


class TextStream(StringIO, QObject):
    inputReceived = pyqtSignal(str)

    def __init__(self, buf=''):
        StringIO.__init__(self, buf)
        QObject.__init__(self)

    def write(self, s):
        StringIO.write(self, s)
        self.inputReceived.emit(s)
        

def main(args=[]):
    app = QApplication(args)
    sys.stdout = TextStream()
    textEdit = QTextEdit()
    sys.stdout.inputReceived.connect(textEdit.setText)
    textEdit.show()
    sys.stdout.write('Spam')
    app.exec_()


if __name__ == '__main__':
    main(sys.argv)
Ein paar Anmerkungen: Es existiert zwar `QTextStream`, aber ich finde es als Ersatz für `sys.stdout` eher ungeeignet. Daher der Rückgriff auf das hier schon erwähnte `StringIO`. Wie man sieht, habe ich mich entschieden, eine Art abstrakte Zwischenschicht zu schreiben, die ganz in Qt-Manier erstmal nur signalisert, dass neuer Input da ist, ohne dass schon eine spezielle Callback-Funktion oder ein spezifisches Empfänger-Widget angegeben werden müsste. Das mit der expliziten Angabe der beiden `__init__()`-Methoden ließ sich IMHO nicht vermeiden, da beim späteren Verbinden sich `connect()` andernfalls immer beschwert hatte, dass es kein `QObject` übergeben bekommt. Naja, und der Rest sollte eigentlich selbsterklärend sein.
lunar

@snafu Leite von "QObject" und "TextIOBase" ab. "StringIO" ist keine notwendige Basisklasse, und dessen Funktionalität auch nicht nötig. Implementiere die komplette Schnittstelle, und stelle sicher, dass das Signal an jeder Stelle entsprechend ausgelöst wird.
Antworten