Seite 1 von 1

Oberfläche friert ein, Konsole läuft weiter

Verfasst: Freitag 7. Juli 2023, 07:09
von Kahnbein.Kai
Guten Morgen
in diesem Programm soll man eine Int Zahl eingeben und das Programm soll dann jeweils in Sekunden schritten bis zu dieser Zahl zählen. Auf der Konsole klappt die Ausgabe, in Tkinter nicht.
Die Programmoberfläche friert bei mir ein und zeigt dann nur den letzten Wert an. Kann mir jemand erklären warum die Oberfläche nicht jede Sekunde aktualisiert wird ?

Code: Alles auswählen

import tkinter as tk

class Programm(tk.Tk):
    
    def __init__(self):
        super().__init__()
        
        self.entry1 = tk.IntVar(self)
        
        self.label1 = tk.StringVar(self, "Ausgabe")
        
        self.Entry1 = tk.Entry(self, textvariable=self.entry1)
        self.Entry1.pack()     
        
        self.Label1 = tk.Label(self, textvariable=self.label1)
        self.Label1.pack()
        
        self.Button1 = tk.Button(self, text="Start", command=self.start)
        self.Button1.pack()
        
        
    def start(self):
        runden = int(self.entry1.get())
        if runden > 0:
            self.counter(runden)
        else:
            self.label1.set("Bitte Zahl > 0 eingeben !!")
        
    def counter(self, runden):
        for j in range(runden):
            print(j)
            self.after(1000, self.update(j))
        
    def update(self,zahl):
        self.label1.set(str(zahl))
        
        
def main():
    root = Programm()
    root.mainloop()
        
        
if __name__ == "__main__":
    main()
Gruß Kai

Re: Oberfläche friert ein, Konsole läuft weiter

Verfasst: Freitag 7. Juli 2023, 09:36
von peterpy
Hallo Kai,
dir fehlt ein update_idletasks,
bitte schreib die Variablennamen klein.

Code: Alles auswählen

import tkinter as tk

class Programm(tk.Tk):    
    def __init__(self):
        super().__init__()        
        self.entry_var = tk.IntVar(self)        
        self.label_var = tk.StringVar(self, "Ausgabe")        
        self.entry = tk.Entry(self, textvariable=self.entry_var)
        self.entry.pack()             
        self.label = tk.Label(self, textvariable=self.label_var)
        self.label.pack()        
        self.button = tk.Button(self, text="Start", command=self.start)
        self.button.pack()        
        
    def start(self):
        runden = int(self.entry_var.get())
        if runden > 0:
            self.counter(runden)
        else:
            self.label_var.set("Bitte Zahl > 0 eingeben !!")
        
    def counter(self, runden):
        for j in range(runden):
            self.update(j)
            print(j)
            self.after(1000)
        
    def update(self,zahl):        
        self.label_var.set(str(zahl))
        self.update_idletasks()
        
        
def main():
    root = Programm()
    root.mainloop()
        
if __name__ == "__main__":
    main()
Gruss Peter

Re: Oberfläche friert ein, Konsole läuft weiter

Verfasst: Freitag 7. Juli 2023, 10:16
von Sirius3
@peterpy: update_ideltasks sollte man nicht benutzen, statt dessen sollte man after benutzen, so wie Du das machst, hat das aber keinen Effekt.

@Kahnbein.Kai: das selbe Thema hatten wir doch schon vor einiger Zeit hier: viewtopic.php?p=384851
Lang laufende Schleifen darf es bei tkinter nicht geben, das Argument von after muß eine Funktion sein, und nicht der Rückgabewert nach dem Aufruf der Funktion update.
Es ist sehr verwirrend, dass es ein Attribut entry1 gibt (was gar kein Entry ist) und eins mit dem selben Namen Entry1. Variablennamen, schreibt man generell komplett klein. Man nummeriert keine Variablen durch, die 1 ist überflüssig und kann weg.

Code: Alles auswählen

import tkinter as tk

class Programm(tk.Tk):    
    def __init__(self):
        super().__init__()        
        self.entry_var = tk.IntVar(self)        
        self.label_var = tk.StringVar(self, "Ausgabe")        
        self.entry = tk.Entry(self, textvariable=self.entry_var)
        self.entry.pack()             
        self.label = tk.Label(self, textvariable=self.label_var)
        self.label.pack()        
        self.button = tk.Button(self, text="Start", command=self.start)
        self.button.pack()        
        
    def start(self):
        runden = int(self.entry_var.get())
        if runden > 0:
            self.counter(0, runden)
        else:
            self.label_var.set("Bitte Zahl > 0 eingeben !!")
        
    def counter(self, aktuelle_runde, runden):
        if aktuelle_runde < runden:
            aktuelle_runde += 1
            self.label_var.set(str(aktuelle_runde))
            self.after(1000, self.counter, aktuelle_runde, runden)
        
        
def main():
    root = Programm()
    root.mainloop()
        
if __name__ == "__main__":
    main()

Re: Oberfläche friert ein, Konsole läuft weiter

Verfasst: Freitag 7. Juli 2023, 10:17
von peterpy
oder nur ein einfaches

Code: Alles auswählen

self.label.update()
wenn Du die Methode update vor after aufrufst.
Das vorher Aufrufen hat auch den positiven Effekt, dass die Ausgabe synchron zur Konsolenausgabe angzeigt wird.
Gruss Peter

Re: Oberfläche friert ein, Konsole läuft weiter

Verfasst: Freitag 7. Juli 2023, 11:18
von __blackjack__
@peterpy: `update()` noch weniger als `update_idletasks()`. Mit so einem Unsinn sollte man gar nicht erst anfangen. Das skaliert nicht, und wenn es etwas komplexer wird, dann hat man schnell undefinierten Zustand, also das Programm läuft oder es stürzt hart ab, oder irgendwas dazwischen. Bei `update()` muss man das mit der Ereignisschleife sehr gut verstehen, weil das Beschränkungen hat was da passieren darf und was nicht wenn man `update()` aus einem Callback heraus aufruft. Und insbesondere bei solchen Fällen wie hier, wo das ja ganz offensichtlich benutzt werden soll um sich gerade nicht mit er Ereignisschleife zu beschäftigen, weil das nicht verstanden worden ist, ist das gefährlich.

Auch bei Korrekter verwendung von `after()` ist eine parallele Ausgabe auf der Konsole synchron. Das ist also kein Argument.