Consolenausgabe in tkinter

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
Duesentrieb
User
Beiträge: 52
Registriert: Sonntag 16. März 2014, 17:14

Hallo,

zur Ausgabe meiner Terminalmeldungen in einem Formular mit tkinter habe ich den nachfolgenden Code gefunden und erfolgreich eingebaut:

Code: Alles auswählen

import Tkinter as tk
import sys
class TkConsole:
    def __init__(self):
        self.console= tk.Text(width=80, height=20)
        self.console.pack()
    def write(self, text):
        self.console.insert("end", text)

c = TkConsole()
sys.stdout = c
print "Ich bin ein Testingteststring"
tk.mainloop()
Jetzt möchte ich diesem Fenster noch eine Scrolleiste geben und den ausgegebenen Text nach oben laufen lassen.
Was muss ich dafür tun?
Benutzeravatar
__blackjack__
User
Beiträge: 14076
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Duesentrieb: Erst einmal sollte man nichts mehr in Python 2 anfangen.

Dann ist es unsauber kein Master zu übergeben. Letztlich verbaut man sich damit auch die Möglichkeit das in eine GUI einzubinden die aus mehr als einem impliziten Hauptfenster besteht. Ebenso das `pack()` in der `__init__()` verhindert das man dieses Widget beispielsweise in ein `grid()` setzen kann.

`c` ist kein guter Name. Falls das für `console` stehen soll, dann sollte man das auch so schreiben.

Für das Umleiten von der Standardausgabe hat das `contextlib`-Modul eine Funktion die die Ausgabe auch wieder zurücksetzt.

Es gibt da bereits etwas von Ratio…, äh, in der Standardbibliothek: `ScrolledText`.

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from contextlib import redirect_stdout
from tkinter.scrolledtext import ScrolledText


class TkConsole(ScrolledText):
    def write(self, text):
        self.insert(tk.END, text)


def main():
    root = tk.Tk()
    console = TkConsole(root, width=80, height=20)
    console.pack()
    with redirect_stdout(console):
        print("Ich bin ein Testingteststring")
        root.mainloop()
    print("Bye...")


if __name__ == "__main__":
    main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Duesentrieb
User
Beiträge: 52
Registriert: Sonntag 16. März 2014, 17:14

Hallo __blackjack__
Danke für deine Hinweise. Ich bin bereits selbst dran, den Code anzupassen. Das war nur eine Kopie eines alten Beitrages hier im Forum.
Mit deinem Hinweis hast du mir aber sehr gut geholfen!
Schöne Güße
Duesentrieb
User
Beiträge: 52
Registriert: Sonntag 16. März 2014, 17:14

Hallo,
jetzt benötige ich doch noch einmal Unterstützung:

Zur Übertragung der Print Ausgaben in das Fenster dient doch "sys.stdout". Wenn ich nun "sys.stdout = main()" eingeb, müsste es doch umgeleitet werden.
Leider geht hier aber nur ein neues Fenster auf das leer bleibt.

Wo liegt mein Denkfehler?
Sirius3
User
Beiträge: 18278
Registriert: Sonntag 21. Oktober 2012, 17:20

Was denkst Du, ist der Rückgabewert von `main()`?
Duesentrieb
User
Beiträge: 52
Registriert: Sonntag 16. März 2014, 17:14

Das ist ja genau dass was ich nicht verstehe!
Die Console wird bei main geöffnet.
Ich weis aber nicht wie ich die Printausgabe in die Übergabe bekommen
Benutzeravatar
__blackjack__
User
Beiträge: 14076
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Duesentrieb: Von welchem Code reden wir denn hier? Was steht in `main()`? Und wo steht dann die Zeile ``sys.stdout = main()``? `main()` ist ja eigentlich die Hauptfunktion, wie kann so eine Zeile dann ausserhalb stehen?
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Duesentrieb
User
Beiträge: 52
Registriert: Sonntag 16. März 2014, 17:14

o.k. dann bin ich jetzt völlig auf dem Holzweg!

Dann muss ich dich fragen wie ich über deinen Code eine Umleitung der Printausgaben in die main()-Funktion erhalte?

Code: Alles auswählen

if __name__ == "__main__":
    main()
in das Hauptprogramm zu nehmen kann es ja nicht sein
Benutzeravatar
__blackjack__
User
Beiträge: 14076
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Duesentrieb: Ich verstehe die Frage nicht. Mein Beispielcode leitet die `print()`-Ausgaben die passieren während sich der Programmfluss in dem ``with``-Block befindet, in das Tk-Fenster um.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Duesentrieb
User
Beiträge: 52
Registriert: Sonntag 16. März 2014, 17:14

wenn ich den Code so anpasse:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from contextlib import redirect_stdout
from tkinter.scrolledtext import ScrolledText


class TkConsole(ScrolledText):
    def write(self, text):
        self.insert(tk.END, text)
        def main():
    root = tk.Tk()
    console = TkConsole(root, width=80, height=20)
    console.pack()
benötige ich doch einen verweis auf die Klasse bzw. Funktion.
Ich ging davon aus dass ich dafür

Code: Alles auswählen

 ``sys.stdout = main()``
im Hauptprogramm einsetzen muss.

Das war falsch bzw. führt nur dazu dass ein Fenster auf geht und die Ausgaben verschwinden.
Wodurch soll die Umleitung entstehen wenn die Verweise fehlen?
Sirius3
User
Beiträge: 18278
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum solltest Du ein funktionierendes Beispiel so anpassen wollen, dass die wesentlichen Zeilen fehlen?
Deine Einrückung ist kaputt.
Um eine sinnvolle Konsolenausgabe zu haben, braucht man ja noch andere Funktionen, die bei bestimmten Aktionen etwas ausgeben. Da würde ich aber was mit logging nachen. Oder man hat einen lange laufenden Prozess der regelmäßig etwas meldet. Dann braucht man aber nebenläufige Progeammierung, mit allen Komplikationen, die sowas mitsichbringt: queues after etc.
Was willst Du machen?
Duesentrieb
User
Beiträge: 52
Registriert: Sonntag 16. März 2014, 17:14

Hallo,
wie gesagt, in dem Beispiel von blackjack wird ja nur Teststring ausgegeben nachdem der Sprung auf die Funktion erfolgt ist.
Ich möchte einige Zwischenmeldungen meines Testprogramms, einer Messwerterfassung, anzeigen lassen.

Mein Code hat ja auch schon funktioniert.
Leider fehlt mir hier aber der Scrollbalken so dass ich die Frage gestellt habe:

Code: Alles auswählen

import Tkinter as tk
import sys
class TkConsole:
    def __init__(self):
        self.console= tk.Text(width=80, height=20)
        self.console.pack()
    def write(self, text):
        self.console.insert("end", text)

console = TkConsole()
sys.stdout = console
print "Ich bin ein Testingteststring"
tk.mainloop()
Nachvollziehbar ist für mich dass ich eine Umleitung für alle Ausgaben über "sys.stdout = console" erhalte. So etwas fehlt im Beispiel von blackjack
Sirius3
User
Beiträge: 18278
Registriert: Sonntag 21. Oktober 2012, 17:20

Nein, das fehlt nicht, weil man es korrekterweise mit `redirect_stdout` macht, statt sys.stdout irgendwas direkt zuzuweisen.
Benutzeravatar
bi3mw
User
Beiträge: 11
Registriert: Mittwoch 19. Oktober 2022, 23:14

Hallo, ich habe es folgendermaßen hinbekommen eine Scrollbar anzufügen:

Code: Alles auswählen

import Tkinter as tk
import sys
master = tk.Tk()
class TkConsole:
    def __init__(self):
        self.console= tk.Text(master, width=80, height=20)
        scroll_bar = tk.Scrollbar(master)
        scroll_bar.pack(side=tk.RIGHT)
        self.console.pack(side=tk.LEFT)
        self.console.config(yscrollcommand=scroll_bar.set)
        scroll_bar.config(command=self.console.yview)
    def write(self, text):
        self.console.insert(tk.END, text)
        
c = TkConsole()
sys.stdout = c
print "Ich bin ein Testingteststring"
tk.mainloop()
Antworten