@v1000: Sternchen-Importe sind Böse™. Da holt man sich gerade bei `tkinter` fast 140 Namen ins Modul von denen nur ein kleiner Bruchteil verwendet wird. Auch Namen die gar nicht in `tkinter` definiert werden, sondern ihrerseits von woanders importiert werden. Das macht Programme unnötig unübersichtlicher und fehleranfälliger und es besteht die Gefahr von Namenskollisionen.
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).
Namen sollten keine kryptischen Abkürzungen enthalten oder gar nur daraus bestehen. Der Name soll dem Leser vermitteln was der Wert dahinter im Programm bedeutet, nicht zum rätseln zwingen.
Man nummeriert keine Namen. Dann will man sich entweder bessere Namen überlegen, oder gar keine Einzelnamen/-werte verwenden, sondern eine Datenstruktur. Oft eine Liste.
GUI-Elemente würde ich in der Reigenfolge anlegen in der sie auch in der GUI angezeigt werden. Es ist so schon nicht so einfach sich über den Code die GUI vorzustellen, das wird nicht besser wenn die Reihenfolge im Code scheinbar gar keinen Zusammenhang mit der Reihenfolge in der GUI hat.
Beim `grid()` sollte man nicht so grosszügig freie Zeilen und Spalten lassen. Wie das angezeigt wird, also ob und wie viel Platz freie Zeilen und Spalten haben, ist von der Plattform abhängig. Das ist also kein robuster Weg um Platz in der GUI zu lassen.
An einige Namen wird sinnloserweise der Rückgabewert von `grid()` gebunden. Der ist `None`. Immer.
`n` und `fa_select` werden zweimal erstellt, aber nur einmal verwendet. Beides sind keine guten Namen, weil sie kryptische Abkürzungen enthalten bzw. im Fall von `n` nur eine kryptische Abkürzung ist. `n` geht gerade mal so als Name für eine ganze Zahl, die eine Anzahl beschreibt, obwohl das auch schon recht ”mathematisch” ist, aber das ist sicher kein sinnvoller Name für ein `StringVar`-Objekt das einen Farbnamen enthält.
`farbe` steht nicht für *eine* Farbe, sondern für mehrere Farben. Die Zuweisung einer leeren Liste ist unnötig, die wird ja überhaupt nicht verwendet. Die „list comprehension“ ist so ein bisschen sinnlos weil die nur die Elemente aus der Datei in die Liste kopiert. Entweder macht man das kürzer durch einen Aufruf von `list()`, oder man macht tatsächlich etwas sinnvolles in der Comprehension — zum Beispiel die Zeilenenden entfernen.
Der `current()`-Aufruf macht an der Stelle so keinen Sinn.
Beim öffnen von Textdateien sollte man immer explizit die Kodierung angeben.
Funktionen (und Methoden) bekommen alles was sie benötigen als Argument(e) übergeben. `berechnen()` braucht also die beiden `StringVar`-Objekte die darin verwendet werden. Bei sehr einfachen GUI Programmen kommt man manchmal mit `functools.partial()` aus, aber für jede nicht-triviale GUI kommt man um objecktorientierte Programmierung (OOP) nicht herum. Also eigene Klassen schreiben.
`Seitenlänge` ist überflüssig. Ab da ist der selbe Wert unter zwei Namen verfügbar. Da der erste nicht mehr benutzt wird, hätte man gleich `seitenlaenge` als Namen verwenden können.
Den ``%``-Operator würde ich nicht mehr zum formatieren von Werten in Zeichenketten verwenden. Dafür gibt es die `format()`-Methode auf Zeichenketten und ab Python 3.6 f-Zeichenkettenliterale.
Das schreiben der CSV-Datei passiert an der falschen Stelle. Vor dem `mainloop()`-Aufruf macht das keinen Sinn. Da war die GUI ja noch gar nicht aktiv und der Benutzer hatte noch gar keine Chance irgend etwas einzugeben oder auszuwählen. Laut Beschriftung der Schaltflächen müsste das in einer Funktion/Methode passieren, die aufgerufen wird, wenn man den „beenden & CSV“-Knopf drückt.
Und dann kann man keine `StringVar`-Objekte oder GUI-Elemente in einer Datei schreiben. Da muss Code stehen der die Werte aus diesen Objekten holt.
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python3
import csv
import tkinter as tk
from functools import partial
from tkinter import ttk
def beenden(root, result_var, farbe_var):
with open("Liste.csv", "w", encoding="utf-8", newline="") as file:
csv.writer(file).writerows(
[
["Position", "Länge", "Farbe"],
[1, result_var.get(), farbe_var.get()],
]
)
root.quit()
def main():
with open("Farben.txt", encoding="utf-8") as lines:
farben = [line.strip() for line in lines]
root = tk.Tk()
root.title("blabla 1.0")
hoehe_var = tk.StringVar()
result_var = tk.StringVar()
farbe_var = tk.StringVar()
tk.Label(text="Farbe").grid(row=1, column=3)
ttk.Combobox(textvariable=farbe_var, values=farben).grid(row=1, column=4)
tk.Label(text="Höhe").grid(row=2, column=0)
tk.Entry(root, textvariable=hoehe_var).grid(row=2, column=1)
tk.Label(text="Seitenlänge").grid(row=3, column=0)
tk.Entry(root, textvariable=result_var, bg="lightgrey").grid(
row=3, column=1
)
tk.Button(
root,
text="berechnen",
command=lambda: result_var.set(f"{float(hoehe_var.get()):.2f}"),
).grid(row=4, column=5, padx=5, pady=5)
tk.Button(
root,
text="CSV schreiben & beenden",
command=partial(beenden, root, result_var, farbe_var),
).grid(row=5, column=5, padx=5, pady=5)
root.mainloop()
if __name__ == "__main__":
main()