18. Aug 2022
Lesedauer 11 Min.
Eigenschaften von Widgets
Grafische Benutzeroberflächen für Python-Programme (Teil 3)
Für die GUI-Programmierung mit Python stellt tkinter Entwicklern verschiedene Techniken zur Verfügung.

Wie kann man Widget-Eigenschaften zur Laufzeit ändern? Wie reagiere ich auf Mouseover- oder auf Mouseleave-Ereignisse oder auf einen Tastendruck oder zum Beispiel auf den Mausklick auf ein Label? Wie definiert man einen Font und ändert ihn bei Bedarf dynamisch? Diese Fragen werden wir im Weiteren beantworten. Außerdem erfahren Sie, wie Sie eigene Fensterklassen erstellen, um sie bei Bedarf in mehreren Programmen zu verwenden.
Widget-Methode after ()
Die Methode after() ist in jeder Widget-Klasse definiert. Sie ruft eine andere Funktion (zweiter Parameter) nach einer in Millisekunden anzugebenden Zeitspanne (erster Parameter) auf. Die Angabe einer Callback-Funktion ist allerdings optional. Wird nur eine Zeitspanne angegeben, dann verhält sich after() wie die Funktion time.sleep(), das heißt, sie hält lediglich die Ausführung des Programms für die angegeben Zeit an.
Wie Sie die Eigenschaften von Widgets festlegen, haben Sie ja bereits gesehen, nämlich indem Sie beim Erstellen eines Widgets den entsprechenden Parametern die gewünschten Werte zuweisen. Eine Schaltfläche mit schwarzer Hintergrundfarbe und weißer Aufschrift definieren Sie so:
button = Button(root, text=<span class="hljs-string">'KLICK MICH!'</span>, <span class="hljs-built_in">bg</span>=<span class="hljs-string">'black'</span>, <span class="hljs-built_in">fg</span>=<span class="hljs-string">'white'</span>)
Was macht man nun aber, wenn sich eine Eigenschaft während der Programmausführung ändern soll? Das tkinter-Modul stellt hierfür in jeder Widget-Klasse eine Methode namens configure() zur Verfügung. Diese Methode ist auch für jedes Widget-Objekt gleich zu verwenden, was die Sache sehr einfach macht. Als Parameter übergeben Sie die Eigenschaften, die Sie ändern wollen und weisen diesen die gewünschten neuen Werte zu. Um die Schaltfläche nach Anklicken mit der Aufschrift DANKE und grünem Hintergrund erscheinen zu lassen, rufen Sie die configure()-Methode so auf:
<span class="hljs-keyword">button</span>.configure(<span class="hljs-keyword">text</span>=<span class="hljs-string">'DANKE'</span>, bg=<span class="hljs-string">'green'</span>)
Wie bereits im ersten Teil der Artikelserie beschrieben, geschieht dies in einer separaten Methode und beim Erstellen des Buttons wird zusätzlich der command-Parameter mit dem Namen der Methode übergeben (Bild 1).

Die Optionen von Widgetssind in einem Dictionary gespeichert(Bild 1)
Saumweber
Hier der komplette Code des Szenarios:
<span class="hljs-title">from</span> tkinter <span class="hljs-keyword">import</span> *
def change_button():
button.configure(text='<span class="hljs-type">DANKE</span>', bg='green')
root = Tk()
root.title('')
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
button = Button(root, text='<span class="hljs-type">KLICK</span> <span class="hljs-type">MICH</span>!', bg='black', fg='white', command=change_button)
button.grid(row=0, column=0)
mainloop()
Der lesende Zugriff auf eine Widget-Eigenschaft erfolgt mit der Methode cget(). Dieser übergeben Sie die Eigenschaft, die Sie abfragen wollen, als String. Im folgenden Listing sorgt die Funktion change_bg_color() dafür, dass die Hintergrundfarbe des Fensters zwischen Rot, Grün und Blau wechselt:
<span class="hljs-keyword">from</span> tkinter <span class="hljs-keyword">import</span> *
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">change_bg_color</span><span class="hljs-params">(widget, sec)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">change</span><span class="hljs-params">()</span>:</span>
<span class="hljs-keyword">if</span> widget.cget(<span class="hljs-string">'bg'</span>) == <span class="hljs-string">'red'</span>:
widget.configure(bg=<span class="hljs-string">'green'</span>)
<span class="hljs-keyword">elif</span> widget.cget(‚bg<span class="hljs-string">') == '</span>green<span class="hljs-string">':</span>
<span class="hljs-string"> widget.configure(bg='</span>blue<span class="hljs-string">')</span>
<span class="hljs-string"> elif widget.cget(‚bg'</span>) == <span class="hljs-string">'blue'</span>:
widget.configure(bg=<span class="hljs-string">'red'</span>)
widget.after(sec * <span class="hljs-number">1000</span>, change)
widget.after(sec * <span class="hljs-number">1000</span>, change)
root = Tk()
root.title(<span class="hljs-string">''</span>)
root.grid_rowconfigure(<span class="hljs-number">0</span>, weight=<span class="hljs-number">1</span>)
root.grid_columnconfigure(<span class="hljs-number">0</span>, weight=<span class="hljs-number">1</span>)
label = Label(root, text=<span class="hljs-string">'Farbwechsel'</span>, bg=<span class="hljs-string">'red'</span>, fg=<span class="hljs-string">'white'</span>, width=<span class="hljs-string">'40'</span>, height=<span class="hljs-string">'20'</span>)
label.grid(row=<span class="hljs-number">0</span>, column=<span class="hljs-number">0</span>)
change_bg_color(label, <span class="hljs-number">3</span>)
mainloop()
In die Funktion change_bg_color() ist die Funktion change() geschachtelt, die von der Funktion change_bg_color() nach drei Sekunden aufgerufen wird. Danach ruft die Funktion change() sich immer wieder selbst auf: widget.after(sec * 1000, change). Für den Parameter sec wurde beim Aufruf von change_bg_color() der Wert 3 übergeben, daher beträgt die Verzögerung jeweils drei Sekunden (sec * 1000).
Direkter Zugriff mit dem []-Operator
<span class="hljs-keyword">if</span> widget[<span class="hljs-string">'bg'</span>] == <span class="hljs-string">'red'</span><span class="hljs-symbol">:</span><br/><span class="hljs-symbol">widget</span>[<span class="hljs-string">'bg'</span>] = <span class="hljs-string">'green'</span>
Die Funktion change() prüft mit cget(), welche Farbe das Widget aktuell hat, und wechselt zur jeweils nächsten Farbe, von Rot also beispielsweise zu Grün (im Beispiel bestimmt die Farbe des Labels auch die Hintergrundfarbe des Fensters, da das Label das Fenster komplett ausfüllt):
if widget.cget('bg') == 'red':
widget.configure(bg='green')
Es gibt mehrere Widgets, die in irgendeiner Weise Text anzeigen, wie zum Beispiel die Aufschrift einer Schaltfläche oder der Text eines Labels, oder es dem Benutzer erlauben, Text einzugeben, wie zum Beispiel Eingabefelder oder das Text-Widget, das wie ein Editor funktioniert (das Text-Widget werden Sie noch kennenlernen). Alle diese Widgets verwenden vordefinierte Font-Einstellungen, die in der Regel sinnvoll sind, sodass Sie diese nicht notwendigerweise selbst festlegen müssen. In manchen Situationen möchte man es aber trotzdem tun, zum Beispiel wenn eine Schaltfläche besonders hervorgehoben werden soll oder bei einem wichtigen Hinweis (Label), oder einfach, weil eine bestimmte Schriftgröße oder eine bestimmte Schriftart gut zum übrigen Design passen.
Font-Tupel und Font-Objekt
Die Font-Einstellungen von Text können Sie wahlweise über ein Tupel oder über ein von tkinter im Modul font zur Verfügung gestelltes Objekt ändern. Wenn Sie zum Beispiel für die Aufschrift einer Schaltfläche die Schriftart Arial, eine Schriftgröße von 24 Punkten sowie einen fetten Schriftstil festlegen wollen, dann können Sie dies folgendermaßen tun:
button = Button(root, text='Klick mich!', font=('Arial', 24, 'bold'))
Im font-Tupel geben Sie zunächst die Schriftart an, dann als Integer die gewünschte Schriftgröße und wiederum als String die gewünschten Schriftstile – hier ist es nur einer; mit der Angabe bold bestimmen Sie eine fette Schrift. Falls Sie mehrere Schriftstile festlegen wollen, trennen Sie diese mittels Leerzeichen – die Reihenfolge spielt hier keine Rolle. Die Angabe font=(‚Arial', 24, ‚bold italic underline') formatiert den Text zum Beispiel fett und kursiv und unterstreicht ihn (Bild 2).

Übergeben Sie beim Erzeugeneines Widget-Objekts den Parameter font mit den entsprechenden Werten(Bild 2)
Saumweber
Wenn der Name der Schriftart keine Leerzeichen enthält, können Sie alternativ auch alle Angaben in einem einzigen String notieren, ebenfalls in der Reihenfolge Schriftart, Schriftgröße, Schriftstile:
button = Button(root, text='Klick mich!', font='Arial 24 bold italic underline')
Mögliche Angaben für Schriftstile sind bold (fett), italic (kursiv), underline (unterstrichen), overstrike (durchgestrichen) – die Standardeinstellung ist normal. Falls sich die Font-Einstellungen zur Laufzeit ändern sollen, setzen Sie das wie beschrieben mit der Methode configure() um. Im folgenden Beispiel wird der Text der Schaltfläche durchgestrichen und der Unterstrich verschwindet, nachdem sie einmal angeklickt wird. Die übrigen Font-Einstellungen bleiben die gleichen:
from tkinter import *
def change():
button.configure(font='Arial 24 bold italic
overstrike')
root = Tk()
root.title('Font definieren')
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
button = Button(root, text='Klick mich!', font='Arial 24 bold italic underline', command=change)
button.grid(row=0, column=0)
mainloop()
Um mit der Font-Klasse Objekte erstellen zu können, müssen Sie das Modul font importieren, zum Beispiel mit from tkinter.font import *, wenn Sie die Klasse im Weiteren direkt ansprechen wollen. Der __init__()-Methode übergeben Sie beim Erstellen eines Font-Objekts die gewünschten Parameter für Schriftart, Schriftgröße usw. Möglich sind folgende Schlüsselwortparameter:Das folgende Listing definiert drei benannte Font-Objekte font1, font2, font3 und weist sie den Label-Elementen label1, label2, label3 zu. Das Ergebnis sehen Sie in Bild 3:
from tkinter.font import *
from tkinter import *
root = Tk()
root.title(‚Font definieren')
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_columnconfigure(2, weight=1)
font1 = Font(family="Helvetica", size=60, slant=ITALIC)
font2 = Font(family="Helvetica", size=20, slant=ITALIC)
font3 = Font(family="Helvetica", size=60, slant=ITALIC, weight=BOLD, underline=True)
label1 = Label(root, text='GUI', font=font1)
label1.grid(row=0, column=0)
label2 = Label(root, text='mit', font=font2)
label2.grid(row=0, column=1)
label3 = Label(root, text='tkinter', font=font3)
label3.grid(row=0, column=2)
mainloop()
Gegenüber dem weiter oben beschriebenen Font-Tupel haben benannte Font-Objekte zwei Vorteile. Erstens, man kann sie für mehrere Widgets verwenden. Zweitens – und das ist wirklich eine Besonderheit – werden alle mit einem Font-Objekt verbundenen Widgets automatisch aktualisiert, wenn sich die Werte des Font-Objekts ändern. Das folgende kleine Beispiel demonstriert dieses Verhalten.

Den drei Wörtern(Label-Elementen) sind verschiedene Font-Objekte zugewiesen(Bild 3)
Saumweber
Die Oberfläche besteht aus einem Label mit dem Text GUI mit tkinter sowie einer Schaltfläche mit der Aufschrift change myfont – myfont ist der Name des Fonts, der beiden Widgets zugeordnet ist. Die Funktion change_font(), die per Schaltflächenklick aufgerufen wird, ändert die Einstellungen von myfont, was auch sofort zu sehen ist. Beide Texte – GUI mit tkinter sowie change myfont – präsentieren sich mit den neuen Font-Einstellungen (kleinere Schrift, nicht mehr kursiv und ohne Unterstrich):
from tkinter import *
from tkinter.font import *
def change_font():
myfont.configure(family="Helvetica", size=20,
slant=ROMAN, weight=BOLD, underline=False)
root = Tk()
root.title('Font definieren')
root.grid_rowconfigure(0, weight=1)
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
myfont = Font(family="Helvetica", size=60, slant=ITALIC, weight=BOLD, underline=True)
label = Label(root, text='GUI mit tkinter', font=myfont)
label.grid(row=0, column=0)
button = Button(text='change myfont', font=myfont, command=change_font)
button.grid(row=1, column=0)
mainloop()
Wie Sie an der Anweisung in der Methode change_font() sehen, lassen sich auch die Einstellungen eines Font-Objekts mit der configure()-Methode ändern. Beachten Sie, dass Sie eine geänderte Einstellung gegebenenfalls explizit zurücksetzen müssen. Daher sind in obigem Beispiel die Angaben slant=ROMAN und underline=False beim Aufruf der configure()-Methode zwingend notwendig. Das bloße Weglassen der beiden Parameter würde die Standardeinstellungen – nicht kursiv und nicht unterstrichen – nicht wiederherstellen. Dementsprechend könnte man dagegen auf die erneute Angabe weight=BOLD verzichten, da eine fette Schrift ja bereits bei der Definition des Fonts myfont festgelegt wurde. Wir haben weight=BOLD hier dennoch angegeben, sodass mit der Anweisung myfont.configure(family=“Helvetica“, size=20, slant=ROMAN, weight=BOLD, underline=False) alle Einstellungen des geänderten Fonts auf einen Blick lesbar sind.
Eine Funktion an ein Ereignis binden
Die Ereignisbehandlung von Schaltflächen verläuft denkbar einfach. Wie gezeigt, übergibt man der __init__()-Methode des Button-Objekts den command-Parameter, um auf das Klick-Ereignis zu reagieren. Wie verhält es sich nun aber mit anderen Ereignissen? Die __init__()-Methoden anderer Widgets stellen den Parameter command nicht zur Verfügung. Wie kann man zum Beispiel darauf reagieren, wenn ein Label-Element angeklickt wird, oder wie reagiert man auf einen Tastendruck?Schriftartangaben erzeugen keine Fehler
tkinter versucht Schriftartangaben immer zuzuordnen, auch wenn sie fehlerhaft oder unvollständig sind. Wenn Sie Times notieren, verwendet tkinter gegebenenfalls Times New Roman und wenn Sie beispielsweise versehentlich Aral statt Arial schreiben, dann wird tkinter trotzdem die Schriftart Arial verwenden. Falls sich eine Schriftartangabe nicht zuordnen lässt, verwendet tkinter die für das jeweilige System vorgesehene Standardschriftart.
Eine Funktion, die ausgeführt wird, wenn ein Ereignis eintritt, brauchen Sie natürlich in jedem Fall. Im Unterschied zu den »gewöhnlichen« Funktionen change_font() oder change_bg_color() der vorherigen Beispiele muss diese Ereignisbehandlungsroutine (Callback-Funktion) den formalen Parameter event enthalten. Damit nun die Ereignisbehandlungsroutine beim Eintritt eines bestimmten Ereignisses ausgeführt wird, müssen Sie sie mit dem Ereignis und außerdem mit dem gewünschten Widget verbinden, bei dem das Ereignis abgefangen werden soll, also zum Beispiel Klick-Ereignis eines Labels.Dies geschieht mit der bind()-Methode, die auf dem Widget aufgerufen wird. Sie erhält das Ereignis sowie die Callback-Funktion als Parameter. Um ein Ereignis zu beschreiben, stehen sogenannte Event-Sequenzen zur Verfügung. Das sind nichts anderes als Strings, die den verschiedenen Ereignissen eindeutig zugeordnet sind.Die Event-Sequenz für einen einfachen Mausklick lautet zum Beispiel '<Button-1>'. Zur Demonstration bemühen wir noch einmal das obige Beispiel mit dem Farbwechsel (Funktion change_bg_color()) und ändern es so ab, dass die Farbwechsel nicht automatisch nach jeweils drei Sekunden, sondern per Klick auf das Label erfolgen:
from tkinter import *
def change_bg_color(event):
if label.cget('bg') == 'red':
label.configure(bg='green')
elif label.cget('bg') == 'green':
label.configure(bg='blue')
elif label.cget('bg') == 'blue':
label.configure(bg='red')
root = Tk()
root.title('')
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
label = Label(root, text='Farbwechsel', bg='red', fg='white', width='40', height='20')
label.grid(row=0, column=0)
label.bind('<Button-1>', change_bg_color)
mainloop()
Die Funktion change_bg_color() muss sich in dieser Version nicht mehr selbst aufrufen. Pro Mausklick soll das Label in diesem Szenario ja nur einmal die Farbe wechseln. Folglich muss die Funktion nur prüfen, welche Farbe das Label aktuell hat und sie dementsprechend durch Aufruf der configure()-Methode ändern – von Rot zu Grün, von Grün zu Blau, und von Blau wieder zu Rot. Der event-Parameter ist , wie gesagt, bei Ereignishandlern Pflicht, auch wenn er im Weiteren nicht verwendet wird.
Verfügbare Schriftfamilien auflisten
from tkinter import *<br/>from tkinter.font import *<br/>root = Tk()<br/>print(families(root))
Die Verbindung von Widget – hier das Label – und Ereignishandler stellen Sie mit der bind()-Methode des Widgets her. Zuerst wird dieser Methode das Ereignis in Form einer Event-Sequenz (hier '<Button-1>' für einen einfachen Mausklick) übergeben. Als zweiten Parameter notieren Sie den Namen der Ereignisbehandlungsroutine (ohne Klammern), die ausgeführt werden soll, wenn das Ereignis eintritt:
label.bind('<Button-1>', change_bg_color)
Beim Aufruf einer Ereignisbehandlungsroutine erhält der event-Parameter Informationen zum Ereignis, die Sie gegebenenfalls abfragen können.

Informationen zum Ereignis,wie zum Beispiel hier den x- und y-Wert der Klickposition, erhalten Sie über den event-Parameter(Bild 4)
Saumweber
Bei Klickereignissen geben event.x und event.y zum Beispiel zurück, an welcher Pixelposition innerhalb des Widgets geklickt wurde. Wenn Sie den Code von change_bg_color() zum Beispiel um die folgende Anweisung ergänzen, dann bekommen Sie nach einem Mausklick auf das Label mitgeteilt, an welcher Stelle Sie geklickt haben (Bild 4); die linke obere Ecke des Labels hat die Position 0/0):
label.configure(text=f'Farbwechsel\nGeklickt an Position {event.x}/{event.y}')
Die Tabelle 1 listet alle Mausereignisse mit den zugeordneten Event-Sequenzen auf. Wenn Sie zum Beispiel nicht auf einen Einfachklick, sondern auf einen Doppelklick reagieren wollen, dann notieren Sie für den bind()-Aufruf label.bind('<Double-Button-1>', change_bg_color). Probieren Sie ruhig einmal alle Event-Sequenzen aus.
Tabelle 1: Mausereignisse
|
Tastaturereignisse haben die Besonderheit, dass sie nur an das Fenster selbst gebunden werden können (root.bind(…)). Das ist nur logisch, denn ein Tastaturkürzel soll ja überall zur Verfügung stehen, nicht nur dann, wenn ein bestimmtes Widget den Fokus hat.
Umsetzung bei Tastaturereignissen
Abgesehen davon funktioniert die Umsetzung bei Tastaturereignissen auf die gleiche Art und Weise wie bei Mausereignissen. Die Event-Sequenz für das Drücken der Taste A lautet zum Beispiel '<KeyPress-A>', für das Drücken der Taste B '<KeyPress-B>' und so weiter. Beachten Sie, dass damit ausschließlich die Großbuchstaben gemeint sind. Für die Kleinbuchstaben lauten die Event-Sequenzen ‚<KeyPress-a>', '<KeyPress-b>', '<KeyPress-c>'. '<KeyPress-Left>', '<KeyPress-Right>', '<KeyPress-Up>' und '<KeyPress-Down>' sind die Event-Sequenzen für das Betätigen der Pfeiltasten. Die Eingabetaste sprechen Sie mit der Event-Sequenz '<Return>' an. Um das Loslassen einer Taste abzufangen, verwenden Sie die Event-Sequenz '<KeyRelease-Taste>', wobei »Taste« als Platzhalter zu verstehen ist. Mit der folgenden Anweisung erfolgt im vorherigen Programm der Farbwechsel zum Beispiel nach dem Loslassen der Taste x:
root.bind('<KeyRelease-x>', change_bg_color)
Wenn Sie den Code eines Fensters in eine separate Klasse packen, können Sie ihn, sprich das Fenster, bei Bedarf bequem wiederverwenden, auch in anderen GUI-Anwendungen. Eventuell möchten Sie ja bestimmte Dialogfenster, die Sie selbst eingerichtet haben, in den meisten oder gar in allen Ihren GUI-Programmen verwenden.
Eine eigene App-Klasse definieren
Ein weiterer Vorteil von Fensterklassen: Wenn sich alle Fensterelemente im globalen Namensraum befinden, dann müssen die Eventhandler definiert werden, bevor Sie verwendet werden. Kapselt man dagegen den Code für ein Fenster in einer eigenen Klasse, dann spielt es keine Rolle, an welcher Stelle ein Eventhandler definiert ist. Er steht innerhalb der Klasse überall zur Verfügung. Die Fensterklasse erbt von der Klasse Frame. Im Grunde ist so eine Fensterklasse ja nichts anderes als ein Frame, wie Sie ihn bereits kennengelernt haben. Man packt alle Fensterelemente hinein und fügt den Frame als Ganzes einem übergeordneten Fenster hinzu. Der __init__()-Methode der Fensterklasse wird das übergeordnete Fenster (parent) übergeben, das dann auch an die __init__()-Methode der Basisklasse durchgereicht wird:
class App(Frame):
def __init__(self, parent):
super().__init__(parent)
Im Weiteren fügen Sie der __init__()-Methode der Fensterklasse die gewünschten Widgets hinzu. Den __init__()-Methoden der Widgets übergeben Sie dabei als ersten Parameter self, da ja die Fensterklasse selbst nun das übergeordnete Fenster darstellt. Zur Demonstration definieren wir eine entsprechende Fensterklasse für unseren Kilojoule-Kilokalorien-Umrechner. Hier der Code der Klasse, inklusive der Methode calculate_kcal(), die nun als Eventhandler fungiert. Der command-Parameter beim Instanziieren des Buttons entfällt, stattdessen wird die Methode an das Klickereignis des Buttons gebunden – self.button.bind('<Button-1>', self.calculate_kcal):
from tkinter import *
class App(Frame):
def __init__(self, parent):
super().__init__(parent)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.frame = Frame(self)
label1 = Label(self.frame, text='Kilojoule')
label1.grid(row=0, column=0, sticky='NESW')
self.entry = Entry(self.frame)
self.entry.grid(row=1, column=0, sticky='NESW')
self.button = Button(self.frame,
text='In Kilokalorien umrechnen')
self.button.grid(row=2, column=0, sticky='NESW')
self.label2 = Label(self.frame,
text='0 Kilokalorien')
self.label2.grid(row=3, column=0, sticky='NESW')
self.frame.grid(row=0, column=0)
self.button.bind('<Button-1>',
self.calculate_kcal)
def calculate_kcal(self, event):
self.label2['text'] = ''
kj = self.entry.get()
if kj.isnumeric():
kcal = round((float(kj) * 0.24), 2)
self.label2['text'] = str(kcal) + ‚
Kilokalorien'
Wie in der vorherigen Version wird ein Frame hinzugefügt – hier mit der Anweisung self.frame = Frame(self) –, in den dann alle Widgets gepackt werden – zum Beispiel label1 = Label(self.frame, text='Kilojoule') – und der danach mit der Anweisung self.frame.grid(row=0, column=0) im Fenster zentriert wird. Der Unterschied ist allerdings, dass der Frame nunmehr der Fensterklasse (self) hinzugefügt wird; in der vorherigen Version war es root, das erstellte Programmfenster. Bezogen auf die Fensterklasse handelt es sich praktisch um einen Frame im Frame.
Auf mehrere Ereignisse gleich reagieren
root.bind('&lt;KeyRelease-f&gt;', change_bg_color)<br/>root.bind('&lt;KeyRelease-F&gt;', change_bg_color)<br/>
Die Methode calculate_kcal() haben wir gegenüber den vorherigen Versionen in zwei Punkten verbessert: Erstens, wir prüfen nun, ob die Eingabe im Feld numerisch ist (if kj.isnumeric():) – nur in diesem Fall wird die Berechnung durchgeführt. Aus einer falschen, nicht als Kilojoule-Wert interpretierbaren Eingabe resultiert somit kein Programmfehler mehr. Zweitens wird der errechnete Kilokalorienwert auf zwei Nachkommastellen begrenzt. Das besorgt die Funktion round(), der der Wert sowie die Anzahl der gewünschten Nachkommastellen zu übergeben ist.
Berechnung starten
Für das Programm definieren wir eine Methode main() und rufen sie anschließend auf. Das Programmfenster wird nun in dieser Methode erstellt (root = Tk()) und mit den üblichen Eigenschaften ausgestattet. Anschließend erzeugen wir mit app = App(root) eine Instanz der oben definierten Fensterklasse mit einer Referenz auf das Programmfenster (root). Mit der Anweisung app.grid(row=0, column=0) packen wir schließlich das app-Fenster in das root-Programmfenster:
def main():
root = Tk()
root.title(‚Kilojoule in Kilokalorien umrechnen')
root.geometry('370x120')
root.minsize(370, 120)
root.maxsize(450, 240)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
app = App(root)
app.grid(row=0, column=0)
root.bind('<Return>', app.calculate_kcal)
root.mainloop()
main()
Die Anweisung root.bind('<Return>', app.calculate_kcal) bindet das Return-Tastaturereignis mit dem Eventhandler calculate_kcal() an das Programmfenster. Somit kann der Benutzer die Berechnung nicht nur per Schaltflächenklick, sondern auch durch Drücken der Eingabetaste starten.