> Python-Kurs: Entry Widgets / Eingabefelder

Eingabefelder / Entry Widgets



Einführung

Eingabefelder auf einer Mauer
Bei einem Entry-Widget oder Eingabefeld handelt es sich um ein Tkinter-Objekt, mit dessen Hilfe beliebiger Text, also ein beleibiger String, in einem einzieligen Eingabefeld vom Benutzer einer Applikation eingegeben werden kann. Falls der Benutzer einen Text eingibt, der mehr Zeichen enthält, als dem Raum des Eingabefeldes entspricht, wird der Text verschoben. Das bedeutet, dass die Anfangsbuchsten des Strings in der Darstellung verschwinden. Mit den Pfeiltasten kann man wieder den Anfang sehen, indem man nach links geht.

Möchte man mehr als eine Zeile Text eingeben, so ist dieses Widget ungeeignet. Man sollte statt dessen ein Text-Widget benutzen.

Die Syntax eines Eingabefeldes sieht wie folgt aus:

w = Entry(master, option, ... )

"master" ist das Eltern-Fenster, indem das Eingabefenster plaziert wird. Wie auch bei anderen Widgets, ist es auch im Fall der Eingabefelder möglich, das Aussehen durch verschiedene Optionen zu beeinflussen. Man kann Entry() jedoch auch ohne Angabe von Optionen starten.

Das folgende einfache Beispiel erzeugt eine einfache Anwendung mit zwei Eingabefeldern. Eine für die Einfabe des Familiennamens und die andere für den Vornamen. Wir benutzen das Default-Entry() ohne Optionen:

from tkinter import *

master = Tk()
Label(master, text="First Name").grid(row=0)
Label(master, text="Last Name").grid(row=1)

e1 = Entry(master)
e2 = Entry(master)

e1.grid(row=0, column=1)
e2.grid(row=1, column=1)

mainloop( )


Das Fenster, welches durch das vorige kleine Python-Programm aufgebaut wird, sieht wie folgt aus:

Eingabefelder für Namen

Gut, wir haben nun ein Fenster mit Eingabefeldern geschaffen, so dass ein Benutzer unseres Programmes Daten eingeben kann. Aber wie kann unser Python-Programm auf diese Daten zugreifen? Wie kann man also den Inhalt der Eingabefelder programmmäßig auslesen?

Langer Rede kurzer Sinn: Tkinter stellt hierfür die get()-Methode zur Verfügung. Wir erweitern unser kleines Skriot um zwei Buttons "Quit" und "Show". An den "Show"-Button binden wir die get()-Methode, um die Eingaben aus den Eingabefeldern auszugeben, d.h. jedes Mal, wenn dieser Knopt gedrückt wird, wird der Inhalt der Eingeabefelder im Terminal, aus dem wir das Skript aufgerufen hatten ausgegeben. Der Quit-Button ist wohl selbsterklärend.

from tkinter import *

def show_entry_fields():
   print("First Name: %s\nLast Name: %s" % (e1.get(), e2.get()))

master = Tk()
Label(master, text="First Name").grid(row=0)
Label(master, text="Last Name").grid(row=1)

e1 = Entry(master)
e2 = Entry(master)

e1.grid(row=0, column=1)
e2.grid(row=1, column=1)

Button(master, text='Quit', command=master.quit).grid(row=3, column=0, sticky=W, pady=4)
Button(master, text='Show', command=show_entry_fields).grid(row=3, column=1, sticky=W, pady=4)

mainloop( )

Starten wir obiges erweiterte Skript erhalten wir folgendes Fenster:

Eingabefelder für Namen plus Show- und Quit-Button

Manchmal ergibt es Sinn eine Anwendung von vordefinierten Werten zu starten. Heißen beispielsweise ein Großteil der Leute, die sich bei unserer Mini-Anwendung eintragen mit Nachnamen "Miller" oder mit Vornamen "Jill", dann könnte es sinnvoll sein die Eingabefelder mit diesen Werten zu initialisieren. Wenn jemand nun "Jill" oder "Miller" heißt, braucht der Name nicht eingeben zu werden.

Die angepasste Version unseres Python-Programmes erhällt nun einfach die folgendenden zwei zusätzlichen Anweisungen, die wir hinter den Definitionen für die Eingabefeldern - also hinter "e2 = Entry(master)" einfügen können:

e1.insert(10,"Miller")
e2.insert(10,"Jill")

Wie sieht es aus, wenn wir die Eingabe in unseren Eingabefeldern jedes Mal löschen wollen, wenn wir sie mittels unserer Funktion show_entry_fields() ausgegeben haben? Kein Problem! Wir haben die delete-Methode. Diese Methode hat das Format delete(first, last=None). Wird nur eine Zahl angegeben, wird das Zeichen an der Position index gelöscht. Werden zwei Zahlen angegeben, so werden alle Zeichen des Bereiches von "first" bis "last" gelöscht.
Um die ganze Eingabe eines Feldes zu löschen, ruft man delete in der Form delete(0, END) auf.

from tkinter import *

def show_entry_fields():
   print("First Name: %s\nLast Name: %s" % (e1.get(), e2.get()))
   e1.delete(0,END)
   e2.delete(0,END)

master = Tk()
Label(master, text="First Name").grid(row=0)
Label(master, text="Last Name").grid(row=1)

e1 = Entry(master)
e2 = Entry(master)
e1.insert(10,"Miller")
e2.insert(10,"Jill")

e1.grid(row=0, column=1)
e2.grid(row=1, column=1)

Button(master, text='Quit', command=master.quit).grid(row=3, column=0, sticky=W, pady=4)
Button(master, text='Show', command=show_entry_fields).grid(row=3, column=1, sticky=W, pady=4)

mainloop( )

Im nächsten Python-Programm zeigen wir, wie wir eine Menge von Eingabefeldern elegant im Python-artig schaffen können. Wir benutzen ein Python-Liste, die die Eingabefeldbeschreibungen enthält, die jeweils in Labels verwendet werden:

#!/usr/bin/python3

from tkinter import *
fields = 'Last Name', 'First Name', 'Job', 'Country'

def fetch(entries):
   for entry in entries:
      field = entry[0]
      text  = entry[1].get()
      print('%s: "%s"' % (field, text)) 

def makeform(root, fields):
   entries = []
   for field in fields:
      row = Frame(root)
      lab = Label(row, width=15, text=field, anchor='w')
      ent = Entry(row)
      row.pack(side=TOP, fill=X, padx=5, pady=5)
      lab.pack(side=LEFT)
      ent.pack(side=RIGHT, expand=YES, fill=X)
      entries.append((field, ent))
   return entries

if __name__ == '__main__':
   root = Tk()
   ents = makeform(root, fields)
   root.bind('<Return>', (lambda event, e=ents: fetch(e)))   
   b1 = Button(root, text='Show',
          command=(lambda e=ents: fetch(e)))
   b1.pack(side=LEFT, padx=5, pady=5)
   b2 = Button(root, text='Quit', command=root.quit)
   b2.pack(side=LEFT, padx=5, pady=5)
   root.mainloop()

Startet man dieses Python-Skript, sieht das Ergebnis wie folgt aus: If you start this Python script, it will look like this:

Name and Job: Bernd Klein, Lecturer, Germany

Taschenrechner

Naja, es wird kein richtiger Taschenrechner, um es gleich zu sagen. Wir erzeugen vielmehr ein Fenster mit einer Eingabezeile, in der ein beliebiger mathematischer Ausdruch eingegeben werden kann und nach der Betätigung der "Return"-Taste berechnet und ausgegeben wird:
from Tkinter import *
from math import *
def evaluate(event):
    res.configure(text = "Ergebnis: " + str(eval(entry.get())))
w = Tk()
Label(w, text="Your Expression:").pack()
entry = Entry(w)
entry.bind("<Return>", evaluate)
entry.pack()
res = Label(w)
res.pack()
w.mainloop()


Das Ergebnis sieht wie folgt aus:

Expression evaluation in Python and Tkinter

Zinsrechnung

Im folgenden umfangreichen Beispiel geht es um Zinsen und Zinseszinsen bei Krediten und deren Berechnung. Wir schreiben eine kleine Tkinter-Oberfläche, um die Eingabewerte zu erfassen. Berechnet werden kann der Kontostand Bk nach k Zahlungen. Gestartet wird mit einem Anfangskapital (ausgegebenes Darlehen / Kredit) und einer Zinsrate pro Periode:

Formula: calculating the monthly payment of a Loan to be paid of in n payment.
where
rate = jährliche Zinsrate in Prozent, z.B. 3 %
i = rate / 100, jährliche Rate in Dezimalform
r = period rate = i / 12
B0 = Kreditsumme (Anfangskapital)
Bk = Stand nach k Zahlungen
k = Anzahl der monatlichen Zahlungen


Möchte man die notwendigen monatlichen Zahlungen ermittlen, falls die Tilgung des Kredites in n Zahlungen erfolgen soll, setzt man Bn = 0 und erhält die folgende Formel:

Formul: monatliche Zahlungen um einen Krdeit in n Zahlungen zu tilgen.
wobei
n = Anzahl der monatlichen Zahlungen um den Kredit zu tilgen.

#!/usr/bin/python3

from tkinter import *
fields = ('Annual Rate', 'Number of Payments', 'Loan Principle', 'Monthly Payment', 'Remaining Loan')

def monthly_payment(entries):
   # period rate:
   r = (float(entries['Annual Rate'].get()) / 100) / 12
   print("r", r)
   # principal loan:
   loan = float(entries['Loan Principle'].get())
   n =  float(entries['Number of Payments'].get())
   remaining_loan = float(entries['Remaining Loan'].get())
   q = (1 + r)** n
   monthly = r * ( (q * loan - remaining_loan) / ( q - 1 ))
   monthly = ("%8.2f" % monthly).strip()
   entries['Monthly Payment'].delete(0,END)
   entries['Monthly Payment'].insert(0, monthly )
   print("Monthly Payment: %f" % monthly)

def final_balance(entries):
   # period rate:
   r = (float(entries['Annual Rate'].get()) / 100) / 12
   print("r", r)
   # principal loan:
   loan = float(entries['Loan Principle'].get())
   n =  float(entries['Number of Payments'].get()) 
   q = (1 + r)** n
   monthly = float(entries['Monthly Payment'].get())
   q = (1 + r)** n
   remaining = q * loan  - ( (q - 1) / r) * monthly
   remaining = ("%8.2f" % remaining).strip()
   entries['Remaining Loan'].delete(0,END)
   entries['Remaining Loan'].insert(0, remaining )
   print("Remaining Loan: %f" % remaining)

def makeform(root, fields):
   entries = {}
   for field in fields:
      row = Frame(root)
      lab = Label(row, width=22, text=field+": ", anchor='w')
      ent = Entry(row)
      ent.insert(0,"0")
      row.pack(side=TOP, fill=X, padx=5, pady=5)
      lab.pack(side=LEFT)
      ent.pack(side=RIGHT, expand=YES, fill=X)
      entries[field] = ent
   return entries

if __name__ == '__main__':
   root = Tk()
   ents = makeform(root, fields)
   root.bind('<Return>', (lambda event, e=ents: fetch(e)))   
   b1 = Button(root, text='Final Balance',
          command=(lambda e=ents: final_balance(e)))
   b1.pack(side=LEFT, padx=5, pady=5)
   b2 = Button(root, text='Monthly Payment',
          command=(lambda e=ents: monthly_payment(e)))
   b2.pack(side=LEFT, padx=5, pady=5)
   b3 = Button(root, text='Quit', command=root.quit)
   b3.pack(side=LEFT, padx=5, pady=5)
   root.mainloop()


Unser Kreditrechner in Python (genaugenommen Python3) sieht nun wie folgt aus:

Kreditrechner in Python unter Benutzung von Tkinter