Tkinter bietet als Basis für alle Widgets eine Vielzahl von Methoden, zu denen unter anderem
die after-Methode gehört. Mit der after-Methode ist es möglich, eine bestehende Funktion oder Methode rekursiv
aufzurufen, nur dass die Funktion sich nicht selbst aufruft, sondern die after-Methode diese Aufgabe übernimmt.
Eine Verwendung der after-Methode hat je nach Anwendung den programmtechnischen Vorteil, dass die Aufrufe nicht
in schneller Folge abgearbeitet werden, sondert entsprechend einer in Millisekunden anzugebenen Verzögerungszeit.
Das erste Beispiel soll nur den Ablauf verdeutlichen, obwohl durchaus lauffähig. In diesem Beispiel würde bei
Aufruf der Funktion mit dem Parameter der Wert 0 an die Funktion übergeben. Parameter dienen der Übergabe, innerhalb
des Kopfes einer Funktion oder einer Methode werden die Parameterwerte an Argumente übergeben, da sich mit Argumenten
besser argumentieren lässt. Im Beispiel beginnt die Argumentation bei 0 und steigert sich bei jedem rekursiven
Aufruf um +1.
Damit die Funktion nicht bis in alle Ewigkeit läuft bzw. nicht ewig rekursiv durch die after-Methode erneut aufgerufen
wird, erfolgt nach 19 +1 = 20 kein erneuter Aufruf. Bis 20 wird jedoch bei Aufruf der Funktion der jeweils aktuelle
Wert ins Label-Widget geschrieben. Die Verzögerungszeit ist im Beispiel auf 100 Millisekunden eingestellt und
so würde in der Ausgabe innerhalb von 2 Sekunden von 1 bis 20 hochgezählt.
Erwähnt sei nebenher, die Zeile mit "argument = argument +1" könnte entfallen, wenn die +1 hinter dem Argument
in der after-Methode notiert wird. In den anderen beiden Beispielen erfolgte die Notation dem Erwähnten entsprechend,
wobei sich das Vorzeichen bei einem Countdown von plus nach minus ändert. Ebenso verändert sich bei einem Countdown
der Anfangswert, da von einer höheren Zahl herab statt herauf gezählt werden soll.
Beispiel Counter:
from tkinter import Tk, Label def starte_counter(argument): # Bedingung erfüllt bis 19 plus 1 if argument < 20: argument = argument +1 # Rekursiver Aufruf, Verzögerungszeit in Millisekunden fenster.after(100, starte_counter, argument) # Schreibt bei jedem Aufruf den veränderten Wert ins Widget. ausgabe["text"] = argument fenster = Tk() fenster.title("Counter") ausgabe = Label(fenster) ausgabe.pack() # Funktionsaufrufe starte_counter(0) fenster.mainloop()
Laufende Ausgabe des Counters von 1 bis 20
Kommt das erste Beispiel noch unscheinbar daher, soll das folgende Beispiel hingegen den minimalen Anforderungen, die ein Programmierer an ein Countdown Script stellt, gerecht werden und etwas mehr einer Anwendung mit einer grafischen Benutzeroberfläche entsprechen. Da beide Varianten das gleiche Ergebnis als Ausgabe liefern, sollten zwei Screenshots genügen.
Ansicht des Widgets beim Start und zur Laufzeit des Countdowns.
Ist der Countdown abgelaufen, ändert sich der eingeblendete Text und die Schrift graut aus.
Ansicht des Widgets am Ende des Countdowns.
Nachfolgend beide Code-Listings, wobei das erste Beispiel etwas einfacher im prozeduralen Stil gehalten ist, das zweite Listing hingegen im objektorientierten Stil.
Code des ersten Tkinter Countdown-Scripts:
from tkinter import Tk, Label def starte_countdown(count): counter["text"] = count # Rekursiver Aufruf der Funktion bis count 0 erreicht ist. if count > 0: # Zeit für rekursive Aufrufe in Millisekunden angeben. fenster.after(1000, starte_countdown, count -1) elif count == 0: fentext["text"] = "Countdown Ende" fentext["fg"] = "#808080" fenster = Tk() fenster.title("Countdown") fenster.wm_iconbitmap("neuronen.ico") fenster.geometry("360x120") fenster["bg"] = "#d9cda3" fentext = Label(fenster, text = "Countdown", fg = "#904b00", font = ("cambria", 12, "bold"), pady = 12, bg = "#d9cda3") counter = Label(fenster, fg = "#40ff40", font = ("cambria", 20, "bold"), relief = "sunken", width = 3, pady = 4, bd = 4, bg = "#000") fentext.pack() counter.pack() # Funktionsaufrufe starte_countdown(10) fenster.mainloop()
Doch nicht nur im Programmierstil unterscheiden sich beide Beispiele. So wird unter anderen im folgenden Script die configure-Methode (config) für durch die Funktion "starte_countdown" gesteuerten Änderungen von Text und Farbe genutzt und für die Ziffern die Klasse StringVar mit der Option "textvariable". Ändert sich der Wert von der Option "textvariable", so wird der Text des Labels aktualisiert.
Code des zweiten Countdown-Scripts im objektorientierten Stil:
from tkinter import Tk, Label, StringVar class CountDown: """Eine Klasse für Widgets mit Countdown""" def __init__(self): self.fenster = Tk() self.fenster.title("Countdown") self.fenster.wm_iconbitmap("neuronen.ico") self.fenster.geometry("360x120") self.fenster.config(background = "#d9cda3") self.zaehler = StringVar() self.fentext = Label(self.fenster, text = "Countdown", fg = "#904b00", font = ("cambria", 12, "bold"), pady = 12, bg = "#d9cda3") self.counter = Label(self.fenster, textvariable = self.zaehler, fg = "#40ff40", font = ("cambria", 20, "bold"), relief = "sunken", width = 3, pady = 4, bd = 4, bg = "#000") self.fentext.pack() self.counter.pack() def starte_countdown(self, count): self.counter = self.zaehler.set(count) if count > 0: self.fenster.after(1000, self.starte_countdown, count -1) elif count == 0: self.fentext.config(text = "Countdown Ende", fg = "#808080") # --- Instanziieren eines Objektes der Klasse CountDown --------------- if __name__ == "__main__": instanz = CountDown() instanz.starte_countdown(10) # Countdown in Sekunden angeben instanz.fenster.mainloop()
Zur Instanziierung sei abschließend noch erwähnt, dass die Bedingung des Statements "__name__ == __main__" nur zutrifft, wenn dieses Script mit der Klasse als eigenes Fenster aufgerufen wird.
Einstieg in Python
OOP mit Python
Codes & Tutorials
Kleines Projekt