Seite 1 von 1
tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 16:37
von Kahnbein.Kai
Hallo,
ich möchte ein tk.Label nach jeder Sekunde aktualisieren lassen.
Das würde auch mit der Methode after(1000, self.Methode) funktionieren, das kann ich leider nicht einsetzen. Da zwei Parameter beim ausführen der Methoden übergeben werden sollen. Daher möchte ich in einer Schleife die time.sleep Methode einsetzten.
Der Code sieht folgendermaßen aus:
Code: Alles auswählen
def zählerGlobal(self, text, Zeit):
for self.zählerUni in range(Zeit):
print(f"{self.zählerUni} / {Zeit}")
self.ausgabe.set(f"Runde: {self.zählerRunde} / {self.runde.get()} {text} {self.zählerUni+1} / {Zeit}")
self.zählerUni += 1
time.sleep(1)
Leider wird die self.ausgabe.set() erst nach Ablauf der Schleife aktualisiert, springt also von 0 Sekunden auf den Endwert.
Ist es Möglich tkinter und die time.sleep Methode zusammen sinvoll zu nutzen ?
Gruß Kai
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 16:51
von Sirius3
Man darf kein sleep benutzen. Statt dessen ist es schon richtig, after zu verwenden. Und da kann man neben einem, drei, vier, fünf, ... dreitausendsiebenhundertneunzehn Parametern auch zwei übergeben. Was aber eigentlich nicht nötig sein sollte, wenn Du eine Klasse hast.
Was hast Du versucht und was hat nicht funktioniert? Zeige vollständigen Beispielcode.
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 17:24
von Kahnbein.Kai
Ok, hier ist die Version A, ich möchte das Programm "optimieren", sodass nicht mehr jede Funktion 'run' und 'unterbrechung' selbst "Zählt" und die Ausgabe aktualisiert.
Code: Alles auswählen
import tkinter as tk
class Programm(tk.Tk):
def __init__(self):
super().__init__()
self.title("Test Ablaufprogramm")
self.runde = tk.IntVar(self, 3)
self.arbeit = tk.IntVar(self, 4)
self.pause = tk.IntVar(self, 2)
self.ausgabe = tk.StringVar(self, "Ausgabe")
tk.Label(self, text='Runden:').grid(row=0,column=2)
tk.Entry(self,width=5, textvariable=self.runde).grid(row=0, column=3)
tk.Label(self, text='Arbeit:').grid(row=0,column=4)
tk.Entry(self,width=5, textvariable=self.arbeit).grid(row=0, column=5)
tk.Label(self, text='Pause:').grid(row=0,column=6)
tk.Entry(self,width=5, textvariable=self.pause).grid(row=0, column=7)
tk.Label(self, textvariable=self.ausgabe).grid(row=2,columnspan=8)
tk.Button(self, text="Start", width=10, command=self.start).grid(row=3, columnspan=8)
self.zählerRunde = 0
def start(self):
self.zählerArbeit = 0
self.zählerPause = 0
self.zählerRunde += 1
self.run()
def run(self):
if self.zählerRunde < self.runde.get():
if self.zählerArbeit < self.arbeit.get()+1:
self.ausgabe.set(f"Runde: {self.zählerRunde} / {self.runde.get()} Arbeit {self.zählerArbeit} / {self.arbeit.get()}")
self.after(1000, self.run)
self.zählerArbeit += 1
else:
self.unterbrechnung()
else:
if self.zählerArbeit < self.arbeit.get()+1:
self.ausgabe.set(f"Runde: {self.zählerRunde} / {self.runde.get()} Arbeit {self.zählerArbeit} / {self.arbeit.get()}")
self.after(1000, self.run)
self.zählerArbeit += 1
else:
self.reset()
def unterbrechnung(self):
if self.zählerPause < self.pause.get()+1:
self.after(1000, self.unterbrechnung)
self.ausgabe.set(f"Runde: {self.zählerRunde} / {self.runde.get()} Pause {self.zählerPause} / {self.pause.get()}")
self.zählerPause += 1
else:
self.start()
def reset(self):
self.ausgabe.set("Ausgabe")
self.zählerRunde = 0
Soweit bin ich im "optimierten" Code
Code: Alles auswählen
import tkinter as tk
class Programm(tk.Tk):
def __init__(self):
super().__init__()
self.title("Test Ablaufprogramm")
self.runde = tk.IntVar(self, 3)
self.arbeit = tk.IntVar(self, 4)
self.pause = tk.IntVar(self, 2)
self.ausgabe = tk.StringVar(self, "Ausgabe")
tk.Label(self, text='Runden:').grid(row=0,column=2)
tk.Entry(self,width=5, textvariable=self.runde).grid(row=0, column=3)
tk.Label(self, text='Arbeit:').grid(row=0,column=4)
tk.Entry(self,width=5, textvariable=self.arbeit).grid(row=0, column=5)
tk.Label(self, text='Pause:').grid(row=0,column=6)
tk.Entry(self,width=5, textvariable=self.pause).grid(row=0, column=7)
tk.Label(self, textvariable=self.ausgabe).grid(row=2,columnspan=8)
tk.Button(self, text="Start", width=10, command=self.start).grid(row=3, columnspan=8)
self.zählerRunde = 0
def start(self):
self.zählerRunde += 1
if self.zählerRunde <= self.runde.get():
self.zählerUni = 0
self.zählerGlobal("Arbeit", self.arbeit.get())
def zählerGlobal(self, text, Zeit):
if self.zählerUni < Zeit:
self.ausgabe.set(f"Runde: {self.zählerRunde} / {self.runde.get()} {text} {self.zählerUni+1} / {Zeit}")
self.zählerUni += 1
self.after(1000,self.zählerGlobal)
Mein Problem ist die letzte Zeile, hier kommt die Fehlermeldung da zwei Argumente benötigt werden. Die Parameter in der Methode Start sind aber nicht die einzigen es gibt noch andere. Daher kann ich die letzte Zeile nicht in
Code: Alles auswählen
self.after(1000, self.zählerGlobal("Arbeit", self.arbeit.get()))
ändern.
Ich weiß nicht wie ich die Methode rekursiv aufrufen soll und die Parameter nur einmal übergeben muss.
Gruß Kai
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 17:30
von Kahnbein.Kai
Ah mir fällt gerade die Methode in einer Methode ein.
Die "Muttermethode" bekommt die PArameter und die "Kindmethode" wird rekursiv ausgeführt.
Könnte das die Lösung des Problem sein ?
Gruß Kai
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 17:52
von Sirius3
So rufst Du ja auch zählerGlobal direkt auf, und nicht per after!
Code: Alles auswählen
self.after(1000, self.zählerGlobal, "Arbeit", self.arbeit.get())
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 18:38
von Kahnbein.Kai
Das mit der Methode innerhalb der Methode geht auch nicht. Das tk.Label wird wieder nicht aktualisiert.
Hier ist der neue Code
Code: Alles auswählen
def start(self):
self.zählerRunde += 1
if self.zählerRunde <= self.runde.get():
self.zählerUni = 0
self.zählerGlobal("Arbeit", self.arbeit.get())
def zählerGlobal(self, text, Zeit):
def zählerIntern():
self.ausgabe.set(f"Runde: {self.zählerRunde} / {self.runde.get()} {text} {self.zählerUni+1} / {Zeit}")
self.zählerUni += 1
if self.zählerUni < Zeit:
self.after(1000, zählerIntern())
zählerIntern()
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 18:50
von Sirius3
Hast Du meinen Beitrag gelesen?
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 19:05
von Kahnbein.Kai
Ja, ich habe es mal versucht es klappt leider nicht.
hier ist der Code:
Code: Alles auswählen
import tkinter as tk
class Programm(tk.Tk):
def __init__(self):
super().__init__()
self.title("Test Ablaufprogramm")
self.runde = tk.IntVar(self, 3)
self.arbeit = tk.IntVar(self, 4)
self.pause = tk.IntVar(self, 2)
self.ausgabe = tk.StringVar(self, "Ausgabe")
tk.Label(self, text='Runden:').grid(row=0,column=2)
tk.Entry(self,width=5, textvariable=self.runde).grid(row=0, column=3)
tk.Label(self, text='Arbeit:').grid(row=0,column=4)
tk.Entry(self,width=5, textvariable=self.arbeit).grid(row=0, column=5)
tk.Label(self, text='Pause:').grid(row=0,column=6)
tk.Entry(self,width=5, textvariable=self.pause).grid(row=0, column=7)
tk.Label(self, textvariable=self.ausgabe).grid(row=2,columnspan=8)
tk.Button(self, text="Start", width=10, command=self.start).grid(row=3, columnspan=8)
self.zählerRunde = 0
def start(self):
self.zählerRunde += 1
if self.zählerRunde <= self.runde.get():
self.zählerUni = 0
self.zählerGlobal("Arbeit", self.arbeit.get())
def zählerGlobal(self, text, Zeit):
self.ausgabe.set(f"Runde: {self.zählerRunde} / {self.runde.get()} {text} {self.zählerUni+1} / {Zeit}")
self.zählerUni += 1
if self.zählerUni < Zeit:
self.after(1000, self.zählerGlobal,"Arbeit", self.arbeit.get())
else:
self.unterbrechung()
def unterbrechung(self):
self.zählerUni = 0
self.zählerGlobal("Pause", self.pause.get())
def main():
root = Programm()
root.mainloop()
if __name__ == "__main__":
main()
Die Abfolge der Ausgabe ist dann so
Arbeit 1/4
Arbeit 2/4
Arbeit 3/4
Arbeit 4/4
Pause 1/2
Arbeit 2/4
Arbeit 3/4
Arbeit 4/4
Pause 1/2
Arbeit 2/4
Arbeit 3/4
...
Die Parameter der Methode 'unterbrechung' werden von der after Methode überschrieben.
Habe ich da ein generellen Denkfehler mit den zwei Methoden für Arbeit und Unterbrechung ?
Gruß Kai
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 19:08
von Sirius3
Kannst Du mal beschreiben, was Du eigentlich erreichen willst?
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 19:30
von Kahnbein.Kai
Ich möchte eine (Zähl) Methode schreiben die zwei Parameter entgegen nimmt. Ein String ("Arbeit" oder "Pause") und je einen Integerwert.
Die Methode 'Start' überträgt die Parameter "Arbeit" und 4 Sekunden. Die Zähl Methode soll jetzt jede Sekunde das Label ändern, mit der Ausgabe "Arbeit" und "X/4 Sekunden".
Im Anschluss soll die Zähl Methode die Parameter "Pause" und 2 Sekunden entgegennehmen, und das Label in "Pause" und "X/2 Sekunden" ändern.
Danach wieder "Arbeit" und "X/4 Sekunden".
Wieder "Pause" und "X/2 Sekunden".
Bis alle Runden durchgelaufen sind, aber das ist erstmal nicht so wichtig. Der große Codeblock im dritten Post läuft.
Darin ist aber alles dreifach jede Methode ändern die Ausgabe und so weiter, ich wollte einfach ein wenig üben und nur eine Methode schreiben, die das Label ändern und Zählt.
Dafür muss diese halt die Parameter übernehmen und die Ausgabe und die Zeit anpassen.
Gruß Kai
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 20:01
von Sirius3
Du rufst ja auch after immer nur mit "Arbeit" auf, da kann der Pausenzähler also auch nie zählen.
Code: Alles auswählen
import tkinter as tk
class Programm(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("Test Ablaufprogramm")
self.runde = tk.IntVar(self, 3)
self.arbeit = tk.IntVar(self, 4)
self.pause = tk.IntVar(self, 2)
self.ausgabe = tk.StringVar(self, "Ausgabe")
tk.Label(self, text='Runden:').grid(row=0,column=2)
tk.Entry(self,width=5, textvariable=self.runde).grid(row=0, column=3)
tk.Label(self, text='Arbeit:').grid(row=0,column=4)
tk.Entry(self,width=5, textvariable=self.arbeit).grid(row=0, column=5)
tk.Label(self, text='Pause:').grid(row=0,column=6)
tk.Entry(self,width=5, textvariable=self.pause).grid(row=0, column=7)
tk.Label(self, textvariable=self.ausgabe).grid(row=2,columnspan=8)
tk.Button(self, text="Start", width=10, command=self.start).grid(row=3, columnspan=8)
def start(self):
self.zaehler_runde = 1
self.zaehler_uni = 1
self.zaehlen("Arbeit", self.arbeit.get())
def zaehlen(self, text, zeit):
self.ausgabe.set(f"Runde: {self.zaehler_runde} / {self.runde.get()} {text} {self.zaehler_uni} / {zeit}")
self.zaehler_uni += 1
if self.zaehler_uni > zeit:
self.zaehler_uni = 1
if text == "Arbeit":
text = "Pause"
zeit = self.pause.get()
else:
self.zaehler_runde += 1
if self.zaehler_runde > self.runde.get():
# Ende
return
text = "Arbeit"
zeit = self.arbeit.get()
self.after(1000, self.zaehlen, text, zeit)
def main():
root = Programm()
root.mainloop()
if __name__ == "__main__":
main()
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Sonntag 14. März 2021, 21:04
von __blackjack__
Die letzte Zeile von `zaehlen` ist falsch eingerückt. Die gehört mit in den ``if``-Zweig.
Hier werden jetzt die beiden `zaehler_*` ausserhalb der `__init__()` als Attribute eingeführt. Die Frage ist, ob die tatsächlich zum Zustand des Objekts gehören, dann sollte man sie in der `__init__()` (mit `None`) einführen, oder ob man die als Argumente an `zaehlen()` übergeben sollte.
Zwei weitere Fragen: Soll man während das läuft die Werte für `self.arbeit` und `self.pause` ändern dürfen? Und ist es tatsächlich in Ordnung wenn man während das läuft noch weitere Vorgänge parallel starten darf, weil ja der Button weiterhin anklickbar ist.
Edit: Und es wird nirgends behandelt, dass der Benutzer auch etwas anderes als Zahlen eintippen könnte und die entsprechenden `get()`-Methoden dann eine Ausnahme auslösen.
Edit 2: Kreative Nutzer könnten auch auf die Idee kommen negative Zahlen einzugeben.
Re: tk.Label während Schleife aktualisieren ?
Verfasst: Montag 15. März 2021, 17:25
von Kahnbein.Kai
@Sirius3
Danke du bist ein Genie !! Ich bin einfach nicht auf die Idee gekommen die übergebenen Parameter in Variablen zu packen und danach die Funktion damit zu füttern.
Vielen Dank !
@__blackjack__
Hier werden jetzt die beiden `zaehler_*` ausserhalb der `__init__()` als Attribute eingeführt. Die Frage ist, ob die tatsächlich zum Zustand des Objekts gehören, dann sollte man sie in der `__init__()` (mit `None`) einführen, oder ob man die als Argumente an `zaehlen()` übergeben sollte.
Naja, darüber habe ich mir noch keine Gedanken gemacht. Ich bin froh, das dass Programm läuft. Wie meinst du das mit '__init__()' und 'None', reicht es nicht wenn ich diese als '=0' deklariere ?
Zwei weitere Fragen: Soll man während das läuft die Werte für `self.arbeit` und `self.pause` ändern dürfen? Und ist es tatsächlich in Ordnung wenn man während das läuft noch weitere Vorgänge parallel starten darf, weil ja der Button weiterhin anklickbar ist.
Nein das ist nicht gewollt. Ich bin noch nicht auf die Idee gekommen zweimal auf Start zu drücken. Ich weiß aber auch nicht wie man das verhindert. Gibt es eine "Art" Sperrfunktion ?
Code: Alles auswählen
Edit: Und es wird nirgends behandelt, dass der Benutzer auch etwas anderes als Zahlen eintippen könnte und die entsprechenden `get()`-Methoden dann eine Ausnahme auslösen.
Darauf bin ich auch noch nicht gekommen, sowas haben wir mal in der Uni gemacht, ich meine das war 'try' und dann wie eine If-Abfrage oder ?
Code: Alles auswählen
Edit 2: Kreative Nutzer könnten auch auf die Idee kommen negative Zahlen einzugeben.
Siehe letzte Antwort
Gruß Kai