Textausgabe mit automatischen Scrollen

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
Epidauros
User
Beiträge: 20
Registriert: Freitag 4. September 2020, 13:47

Hallo zusammen,

ich baue eine SW, die in einem Fenster Aktionen mit Buttons auslöst, und Printausgaben (da können einige hundert Zeilen zusammenkommen) in einem zweiten Fenster. Ich brauche das zweite Fenster, weil das Programm kompiliert werden soll.
Soweit ist auch alles gut und es läuft wie geplant. Fast.
Der Punkt ist: wenn das zweite Fenster voll geschrieben ist und die nächste Zeile wird ausgegeben, dann scrollt der Inhalt im Fenster nicht hoch. Neue Zeilen sind daher nicht lesbar.
Ich benötige eine Konfiguration, die im Fenster immer die letzten ausgegebenen Zeilen durch hochschieben anzeigt.

Ich habe keine Option gefunden, die die Zeilen dann nach oben schiebt.

Code: Alles auswählen

ausgabe = tk.Toplevel()
ausgabe.title("Ausgabefenster")
ausgabe.geometry("350x680")
ausgabe.configure(bg='ivory')
WIN_XPOS = 980
WIN_YPOS = 00
ausgabe.geometry('+{0}+{1}'.format(WIN_XPOS, WIN_YPOS))
label = Label(ausgabe, text=ph+"Informationen und Anzeige der Kommunikation", justify=LEFT)
label.pack()


    info=("Die folgenden sds.ini Parameter wurden geladen:\nPause zwischen Durchführungen [s]: "
            +str(Pause_Default)+"\nPause zwischen zwei Kommandos  [ms]: "
            +str(Pause_AT)+"\nAnzahl Durchführungen:  "
            +str(Durchführungen)+"\nProtocol Identifier:  "
            +str(PID)+"\nSSI:  "
            +str(ssi_default))
    out = Label(ausgabe, text = info, justify=LEFT)
    out.pack()
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

bei StackOverflow gibt es schon so eine Frage mit passender Antwort: https://stackoverflow.com/questions/306 ... n-text-box.

Gruß, noisefloor
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Epidauros: Anmerkungen zum gezeigten Quelltext: Kryptische Abkürzungen in Namen sind keine gute Idee. Noch weniger Namen die ausschliesslich aus einer Kryptischen Abkürzung bestehen. Wenn man `parkhaus` meint, sollte man nicht nur `ph` schreiben.

Das zusammenstückeln von Zeichenketten und Werten mittels ``+`` und `str()` ist eher BASIC als Python. Dafür gibt es die `format()`-Methode auf Zeichenketten und f-Zeichenkettenliterale.

`PID` ist auch kein guter Name wenn er nicht für Prozess-ID steht.

Wo kommen `Label` und `LEFT` her wenn `Toplevel` über `tk` angesprochen wird?

Code: Alles auswählen

WIN_XPOS = 980
WIN_YPOS = 0

...


    ausgabefenster = tk.Toplevel()
    ausgabefenster.title("Ausgabefenster")
    ausgabefenster.geometry("350x680")
    ausgabefenster.configure(bg="ivory")
    ausgabefenster.geometry(f"+{WIN_XPOS}+{WIN_YPOS}")

    tk.Label(
        ausgabefenster,
        text=parkhaus + "Informationen und Anzeige der Kommunikation",
        justify=tk.LEFT,
    ).pack()
    tk.Label(
        ausgabefenster,
        text=(
            f"Die folgenden sds.ini Parameter wurden geladen:\n"
            f"Pause zwischen Durchführungen [s]: {iteration_pause}\n"
            f"Pause zwischen zwei Kommandos  [ms]: {command_pause}\n"
            f"Anzahl Durchführungen:  {iteration_count}\n"
            f"Protocol Identifier:  {protocol_id}\n"
            f"SSI:  {default_ssi}"
        ),
        justify=tk.LEFT,
    ).pack()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Epidauros
User
Beiträge: 20
Registriert: Freitag 4. September 2020, 13:47

Danke! Tut hervorragend!
Auf diesen f String bin ich bisher noch nicht gestossen.

Das einzige, was mich noch stört, ist, dass durch \n getrennte Zeilen zentriert sind, so dass die längste Zeile die Lage der kürzeren Zeilen bestimmt, die dann linksbündig unter der längsten Zeile stehen. Ich hätte gerne alle Zeilen gleich linksbündig am Fenster ausgerichtet. Derzeit behelfe ich mich mittels Parkhaus (:-)), da schicke ich ein "------------------------------------------------------------", und das bestimmt dann die Breite, unterhalb dessen alles linksbündig ausgegeben wird. Nicht schön, ich weiß. Aber ich weiß nicht wie sonst.
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Epidauros: Das verstehe ich nicht so ganz, denn dafür ist doch das ``justify=tk.LEFT`` da‽
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Epidauros
User
Beiträge: 20
Registriert: Freitag 4. September 2020, 13:47

@__blckjack__
das dachte ich auch, aber es kommt anders als man denkt.
Inzwischen habe ich eine andere Methode gefunden, die mir das erledigt.
Dadurch wird immer linksbündig ausgegeben:

Code: Alles auswählen

ausgabe = tk.Toplevel()
S = tk.Scrollbar(ausgabe)
T = tk.Text(ausgabe, height=40, width=50)
S.pack(side=tk.RIGHT, fill=tk.Y)
T.pack(side=tk.LEFT, fill=tk.Y)
S.config(command=T.yview)
T.config(yscrollcommand=S.set)
quote="Mein Text"
T.insert(tk.END, quote)
T.see("end")
Epidauros
User
Beiträge: 20
Registriert: Freitag 4. September 2020, 13:47

@__blckjack__
das dachte ich auch, aber es kommt anders als man denkt.
Inzwischen habe ich eine andere Methode gefunden, die mir das erledigt.
Dadurch wird immer linksbündig ausgegeben:

Code: Alles auswählen

ausgabe = tk.Toplevel()
S = tk.Scrollbar(ausgabe)
T = tk.Text(ausgabe, height=40, width=50)
S.pack(side=tk.RIGHT, fill=tk.Y)
T.pack(side=tk.LEFT, fill=tk.Y)
S.config(command=T.yview)
T.config(yscrollcommand=S.set)
quote="Mein Text"
T.insert(tk.END, quote)
T.see("end")
Epidauros
User
Beiträge: 20
Registriert: Freitag 4. September 2020, 13:47

Hallo zusammen,
Danke noch einmal für die tolle Hilfe.

Jetzt gibt es aber doch noch ein Problem: Ich habe ein Hauptfenster mit Buttons zur Bedienung der Anwendung, und ein Toplevel Fenster mit den Ausgaben, das auch prima scrollt. Aber: Während die nachfolgend dargestellte Aufgabe in einer Schleife läuft, wird nichts im Ausgabefenster ausgegeben. Erst dann, wenn die die Schleifen beendet sind, werden die Ausgaben "nachgeschoben", obwohl die Ausgaben in den Schleifen eingebunden sind

# Hauptfenster

fenster = tk.Tk()
fenster.title("Display-SDS (Autor: DIN)")
WIN_XPOS = 0
WIN_YPOS = 0
fenster.geometry(f"+{WIN_XPOS}+{WIN_YPOS}")

# Ausgabefenster

ausgabefenster = tk.Toplevel()
ausgabe_XPOS=930
ausgabe_YPOS=0
S = tk.Scrollbar(ausgabefenster)
T = tk.Text(ausgabefenster, height=40, width=50)
ausgabefenster.geometry(f"+{ausgabe_XPOS}+{ausgabe_YPOS}")
S.pack(side=tk.RIGHT, fill=tk.Y)
T.pack(side=tk.LEFT, fill=tk.Y)
S.config(command=T.yview)
T.config(yscrollcommand=S.set)

quote="Informationen und Anzeige der Kommunikation"
T.insert(tk.END, quote)
T.see("end")

def dokumentiere(info): # Ausgabe in Ausgabefenster (Toplevel)
quote=f"\n\n"
T.insert(tk.END, quote)
quote=f"\n{info}"
T.insert(tk.END, info)
T.see("end")

def Wiederholung(Durchführungen, Pause_Status): # Durchführungen der Sequenz

wdh=Durchführungen.get()
wdh=int(wdh)
gesamtanzahl = wdh
Durchlauf = 1
print("Durchführung", Durchlauf, "folgt:")

info=(
f"{ph}\n"
f"Durchführung {Durchlauf} folgt:\n")
dokumentiere(info) # Ausgabe in Toplevel Fenster
status_versand(wdh, Pause_Status)
wdh=wdh-1

while wdh != 0:
wdh = wdh-1
Durchlauf = Durchlauf+1
print()
print("------------------------------------")
print()
print("Durchführung", Durchlauf, "folgt:")
info=(
f"{ph}\n"
f"Durchführung {Durchlauf} folgt:\n")
dokumentiere(info) # Ausgabe in Toplevel Fenster
time.sleep(Pause_AT)
status_versand(wdh, Pause_Status)
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Epidauros: In GUI-Code darfst Du nichts langlaufendes machen. Denn wenn Dein Code läuft, dann wird die GUI nicht aktualisiert. Also so etwas wie längere Schleifen und/oder `time.sleep()` geht nicht. Die GUI friert ein, und Änderungen werden erst sichtbar wenn die GUI-Hauptschleife die Kontrolle wieder hat.

Also entweder kannst Du Deinen Code in kleine, kurze Schritte aufteilen und die mit der `after()`-Methode ausführen, oder das muss in einen eigenen Thread. `after()` braucht man dann auch, weil man aus einem anderen Thread heraus nichts an der GUI ändern darf. Das löst man dann mit einer Queue wo der Thread Informationen rein steckt die regelmässig mit `after()` und einer Funktion da heraus genommen und in die Anzeige gesteckt werden.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Epidauros
User
Beiträge: 20
Registriert: Freitag 4. September 2020, 13:47

Hallo Blackjack,
Vielen Dank für deine Ausführungen! Das mit dem einfrieren des Fensters habe ich auch schon festgestellt. Zuerst dachte ich, das wäre ein Bug. Aber anscheinend ist das wohl so zu erwarten.
Mit Threads habe ich noch nie gearbeitet.
Könntest du in meinem Codeschnipsel dazu einen Vorschlag zeigen? Das wäre echt super!
Antworten