@c.schroeder: Vergiss ``global`` sofort wieder und falls noch nicht geschehen, beschäftige Dich mit objektorientierter Programmierung (OOP), denn die braucht man für jede nicht-triviale GUI.
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Damit sind dann auch automatisch die globalen Variablen beseitigt, wenn man kein ``global`` verwendet. Und man muss dann jeder Funktion alles was sie ausser Konstanten benötigt, sauber als Argument(e) übergeben. Womit Programme einfacher nachvollziehbarer und damit auch weniger fehleranfällig werden. Und auch einfacher testbar, weil man Funktionen/Methoden dann isoliert testen kann, ohne vorher schauen zu müssen welchen globalen Zustand man vor dem Aufruf herstellen muss, damit die das richtige tun.
Sternchen-Importe sind Böse™. Da holt man sich gerade bei `tkinter` fast 200 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.
Die Grösse eines Fensters gibt man in der Regel nicht vor, die Ergibt sich automatisch aus dem Inhalt.
Daten und Code wiederholt man nicht. Das macht unnötig Arbeit beim schreiben, und noch mehr beim ändern. So etwas wie die Schriftart für Labels definiert man am Anfang einmal als Konstante. Dann lässt sich das an *einer* Stelle im Code anpassen, und man muss nicht durch den ganzen Code gehen, die Font-Daten suchen, an jeder Stelle entscheiden ob die für die Label-Art sind, die man ändern möchte oder nicht, und an Fundstelle dann gleichartig ändern.
Namen sind wichtig und falls man nicht Meister Yoda ist, dann ist eine `label_frage` etwas anderes als ein `frage_label` und bei `button_anzahl` erwarten die meisten Leser eine Zahl, welche die Anzahl von `button`-Objekten beschreibt, und keine Funktion. Funktionen und Methoden werden üblicherweise nach der Tätigkeit benannt, die sie durchführen. Bei Rückruffunktionen ist auch das Namensmuster `on_*()` üblich, mit einer Beschreibung des Ereignisses auf das die Funktion reagiert. Also beispielsweise `on_submit()` bei etwas das auf eine Benutzerbestätigung hin ausgelöst wird.
Um die Bedingung bei ``if`` (und ``while``) gehören keine Klammern.
Das Ergebnis von `Entry.get()` ist bereits eine Zeichenkette. Das zusammenstückeln von Zeichenketten und Werten mittels ``+`` und `str()` ist eher BASIC als Python. Dafür gibt es die `format()`-Methode auf Zeichenketten und f-Zeichenkettenliterale.
Man nummeriert keine Namen. Schon gar nicht sinnlos lokale Namen die überhaupt gar nicht mit den anderen Namen kollidieren würden.
Und ja, Du kannst nicht sofort nach dem Erstellen eines `Entry`-Objekts dessen Inhalt abfragen. Wie soll denn zu dem Zeitpunkt auf magische Weise schon das drin stehen was der Benutzer erst später überhaupt eingeben kann?
In der Rückruffunktion `button_action2()` wird es dann auch problematisch weil im Gegensatz zum vorhergehenden Schritt *dort* erst das Ausgabelabel erstellt wird. Der Benutzer kann aber mehrfach auf den Button drücken und da wird dann *jedes mal* ein neues Ausgabelabel erstellt. Das muss auch nur *einmal* erstellt werden, und von aussen kommen.
Und um das zu garantieren, muss man jeweils dafür sorgen, das bereits eingegebene Sachen nicht noch einmal bestätigt werden können, man muss also den jeweils vorhergehenden Button auch mit durchreichen und bei erfolgreicher Eingabe deaktivieren.
Zwischenstand wäre dann das hier:
Code: Alles auswählen
#!/usr/bin/env python3
import tkinter as tk
from functools import partial
LABEL_FONT = ("arial", 10, "bold")
def on_height_submit(eingabefeld, ausgabe_label, bestaetigen_button):
text = eingabefeld.get().strip()
if not text:
ausgabe_label["text"] = "Es muss etwas eingegeben werden!"
else:
ausgabe_label["text"] = f"Höhe {text}"
eingabefeld["state"] = bestaetigen_button["state"] = tk.DISABLED
def create_height_entry(fenster):
tk.Label(fenster, text="Höhe: ", font=LABEL_FONT).grid(row=1, column=0)
eingabefeld = tk.Entry(fenster, bd=5, width=20)
eingabefeld.grid(row=1, column=1)
bestaetigen_button = tk.Button(fenster, text="Bestätigen")
bestaetigen_button.grid(row=1, column=2)
ausgabe_label = tk.Label(fenster)
ausgabe_label.grid(row=1, column=3)
bestaetigen_button["command"] = partial(
on_height_submit, eingabefeld, ausgabe_label, bestaetigen_button
)
def on_count_submit(fenster, eingabefeld, ausgabe_label, bestaetigen_button):
text = eingabefeld.get().strip()
if not text:
ausgabe_label["text"] = "Es muss etwas eingegeben werden!"
else:
ausgabe_label["text"] = f"Anzahl: {text}"
eingabefeld["state"] = bestaetigen_button["state"] = tk.DISABLED
create_height_entry(fenster)
def main():
fenster = tk.Tk()
fenster.title("Berechnung WEA:")
tk.Label(fenster, text="Anzahl: ", font=LABEL_FONT).grid(row=0, column=0)
eingabefeld = tk.Entry(fenster, bd=5, width=20)
eingabefeld.grid(row=0, column=1)
bestaetigen_button = tk.Button(fenster, text="Bestätigen")
bestaetigen_button.grid(row=0, column=2)
ausgabe_label = tk.Label(fenster)
ausgabe_label.grid(row=0, column=3)
bestaetigen_button["command"] = partial(
on_count_submit,
fenster,
eingabefeld,
ausgabe_label,
bestaetigen_button,
)
fenster.mainloop()
if __name__ == "__main__":
main()
Da ist jetzt noch nicht berücksichtigt, das man am Ende ja vielleicht etwas mit den ganzen Eingaben machen will. Und da man keine globalen Variablen verwendet, müsste man die gesammelten Eingaben, beispielsweise in einem Wörterbuch, auch immer mit durchreichen, und ganz am Ende dann einer Funktion übergeben, die etwas damit macht.
Am aktuellen Stand fällt auf, dass die Funktionen abwechselnd *sehr* ähnlich sind, und sich nur in einigen wenigen Werten unterscheiden. So etwas macht man nicht, weil auch hier wieder eine Anpassung am Muster das da entsteht x-mal wiederholt werden muss, in jeder Kopie des Codes. Dafür gibt es Funktionen, um wiederholte Muster im Code nicht kopieren zu müssen.
Allerdings sollte man den Ablauf in der GUI hier sowieso mal grundsätzlich in Frage stellen. Warum muss man jede Eingabe bestätigen und bekommt dann erst die nächste? So eine GUI ist keine Konsolenanwendung. Normalerweise bekommt der Benutzer eine Eingabemaske, gibt dort alle seine Werte ein, und drückt dann ”Bestätigen”. Daraufhin läuft Code der *alle* Eingabefelder validiert, und ggf. eine Meldung ausgibt, was da noch falsch ist.