Informatik10/tk_first_steps/feet_classes.py

172 lines
5.1 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
from tkinter import *
from tkinter import ttk
class FeetToMeter(Tk):
def __init__(self):
super().__init__()
self.title("Feet to Meters")
self.status = 1 # 1 - neue Eingabe, 2 - Eingabe verarbeitet
# Event Handler (Validator) registrieren
self.check_entry_wrapper = self.register(self.check_entry)
self.create_styles()
self.create_widgets()
self.bind_events()
def create_styles(self):
""" Erstellen der speziellen Stil-Konfigurationen.
:return:
"""
self.s = ttk.Style()
self.s.configure('aFrame.TFrame', background="yellow")
self.s.configure('bFrame.TFrame', background="green")
self.s.configure('cFrame.TFrame', background="red")
return True
def create_widgets(self):
""" Erstellen der Fenster-Bestandteile.
:return:
"""
# Rahmen im Hauptfenster (aus ttk für Farbanpassung)
mainframe = ttk.Frame(self, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=N+W+S+E)
# mainframe darf sich ausdehnen.
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
# Eingabefeld für Länge in feet
self.feet = StringVar()
feet_entry = ttk.Entry(mainframe, width=7, textvariable=self.feet,
validatecommand=(self.check_entry_wrapper, '%P'),
validate='key')
feet_entry.grid(column=2, row=1, sticky=W+E)
# Einheit-Label für Eingabefeld der Länge in feet
ttk.Label(mainframe, text="feet").grid(column=3, row=1, sticky=W)
# Label für Ausgabefeld der Länge in Metern
ttk.Label(mainframe, text="ist äquivalent zu").grid(column=1, row=2, sticky=E)
# Einheit-Label für Ausgabefeld der Länge in Metern
ttk.Label(mainframe, text="Meter").grid(column=3, row=2, sticky=W)
# Ausgabefeld für Länge in Metern
self.meters = StringVar()
meters_entry = ttk.Entry(mainframe, width=7, textvariable=self.meters)
meters_entry.grid(column=2, row=2, sticky=(W, E))
meters_entry.configure(state='readonly') # keine Eingabe, aber selektierbar
# Button für Berechnung
button_calc = ttk.Button(mainframe, text="Berechne", command=self.calculate)
button_calc.grid(column=3, row=3, sticky=W)
# schönere Abstände
for child in mainframe.winfo_children():
child.grid_configure(padx=5, pady=5)
# Statusbar
self.frame_statusbar = ttk.Frame(self)
self.frame_statusbar['relief'] = 'sunken'
self.frame_statusbar['height'] = 12
self.frame_statusbar['style'] = 'aFrame.TFrame'
self.frame_statusbar.grid_propagate(0) # Feste Größe an Grid-Packer weitergeben
self.frame_statusbar.grid(column=0, row=1, sticky=W+S+E)
# Setze Fokus in Eingabefeld
feet_entry.focus()
def bind_events(self):
""" Ereignisse an Kommandos binden.
:return:
"""
self.bind("<Return>", self.calculate)
self.bind("<KP_Enter>", self.calculate)
def switch_status(self, new_status: int = None):
""" Verändert den globalen Status
:param new_status: neuer Statuswert
:return: None
"""
self.status
if not new_status:
if self.status == 1:
self.status = 2
else:
self.status = 1
else:
self.status = new_status
self.update_statusbar()
def update_statusbar(self):
""" Passt die Farbe der Statuszeile an den Status an.
:return: None
"""
if self.status == 1:
self.frame_statusbar['style'] = 'aFrame.TFrame'
elif self.status == 2:
self.frame_statusbar['style'] = 'bFrame.TFrame'
else:
self.frame_statusbar['style'] = 'cFrame.TFrame'
def calculate(self, *args):
""" Berechnet aus der eingegebenen Länge in feet die Länge in Metern.
:param args:
:return: None
"""
try:
stringvalue = self.feet.get()
stringvalue = stringvalue.replace(",", ".")
value = float(stringvalue)
m_value = 0.3048 * value
m_value = round(m_value, 2)
self.meters.set(m_value)
# Berechnung abgeschlossen.
self.switch_status(2)
except ValueError:
pass
return True
def check_entry(self, what: str = ""):
""" Validiert, ob Eingabe leer oder eine Fließkommazahl ist.
:param what: str eingegebene Zeichenkette
:return: boolean
"""
self.switch_status(1)
if what == "":
# Nichts eingegeben
return True
else:
try:
# DEBUG
print(what)
what = what.replace(',', '.')
float(what)
return True
except ValueError:
return False
if __name__ == "__main__":
app = FeetToMeter()
app.mainloop()