This program takes x numbers and displays the mean, median and mode.
My goal here was to use classes and class properties the best I could to make the code shorter (honestly i may have just made it longer), so I would like to get some feedback on that.
import tkinter as tk
from typing import Callable, List
from statistics import mean, median, mode
"""MainFunctions = initialization creates 2 starting input boxes and the 3 outputs"""
"""Input = initialization creates an entry and stringvar for input"""
"""Output = initialization creates a label for the name of the average and another for the output"""
class Input:
def __init__(self, parent: tk.Tk, index: int, callback: Callable[[], None]) -> None:
self.value_var = tk.StringVar(parent)
self.value_var.trace_add(mode="write", callback=callback)
self.value_entry = tk.Entry(
parent, textvariable=self.value_var
)
self.value_entry.grid(row=index, column=1)
def delete_entry(self) -> None:
self.value_entry.destroy()
@property
def value(self) -> str:
if self.value_var.get():
return self.value_var.get()
else:
return None
@property
def row(self) -> int:
grid_info = self.value_entry.grid_info()
return grid_info['row']
class Output:
def __init__(self, parent: tk.Tk, index: int, name: str) -> None:
self.name = name
self.name_label = tk.Label(parent, text=f"{name}:")
self.name_label.grid(row=index, column=0)
self.output_label = tk.Label(parent, text=0)
self.output_label.grid(row=index, column=1)
def grid(self, row) -> None:
self.name_label.grid(row=row, column=0)
self.output_label.grid(row=row, column=1)
def set_output(self, values) -> None:
try:
match self.name:
case "Mean": self.output_label.configure(text=mean(values))
case "Median": self.output_label.configure(text=median(values))
case "Mode": self.output_label.configure(text=mode(values))
except:
self.output_label.configure(text=0)
class MainFunctions:
def __init__(self, parent: tk.Tk) -> None:
self.parent = parent
self.inputs = [
Input(self.parent, 0, self.input_callback),
Input(self.parent, 1, self.input_callback)
]
self.outputs = [
Output(
self.parent, 2, "Mean"
),
Output(
self.parent, 3, "Median"
),
Output(
self.parent, 4, "Mode"
)
]
def create_destroy_input(self) -> None:
"""Counts the number of empty stringvars"""
empty_stringvars = 0
for input in self.inputs[::-1]:
if input.value == None:
empty_stringvars += 1
"""Deletes all empty entries and stringvars except for 1, then creates another"""
for input in self.inputs[::-1]:
if empty_stringvars <= 1:
self.inputs += [
Input(
self.parent, len(self.inputs), self.input_callback
)
]
return
if input.value == None:
input.delete_entry()
self.inputs.remove(input)
empty_stringvars -= 1
def grid_output(self) -> None:
"""To grid the output according to the how many entries there are"""
row = 1
for output in self.outputs:
output.grid(row + len(self.inputs))
row += 1
def get_values(self) -> List:
"""Gets all values in entries"""
values = []
for input in self.inputs:
try:
value = input.value.replace(",", ".")
values.append(float(value))
except:
pass
return values
def set_output(self, values) -> None:
"""Calls function for setting output 3 times for each output label"""
for output in self.outputs:
output.set_output(values)
def input_callback(self, name: str, mode: str, index: str) -> None:
"""Every stringvar calls back to this"""
self.create_destroy_input()
self.grid_output()
self.set_output(self.get_values())
def main() -> None:
root = tk.Tk()
root.title("Mean, median and mode calculator")
root.resizable(width=False, height=False)
MainFunctions(root)
root.mainloop()
if __name__ == "__main__":
main()