Variable nach schließen der GUI behalten

Fragen zu Tkinter.
Antworten
blubbablas3
User
Beiträge: 10
Registriert: Sonntag 4. August 2019, 12:32

Hallo liebe Mitglieder,

ich versuche gerade eine Variable (vermutlich lokal?) nach beenden der GUI zu behalten um im Anschluss damit zu rechnen. Leider klappt es nicht und daher würde ich mich über Hilfe freuen.
Danke!

# Die folgende Funktion soll ausgeführt werden, wenn
# der Benutzer den Button Klick me anklickt
def button_action():
entry_text = eingabefeld.get()
k = float(entry_text)
if (entry_text == ""):
ausgabe_label.config(text="Geben Sie bitte zuerst k (0<k<1) ein.")
else:
entry_text2 = "Kopplungsfaktor= " + entry_text
ausgabe_label.config(text=entry_text2)

fenster = Tk()
fenster.title("Eingabe: Kopplungsfaktor k.")

# Anweisungs-Label
my_label = Label(fenster, text="Geben Sie den Kopplungsfaktor k ein: ")

# In diesem Label wird nach dem Klick auf den Button der Benutzer
# über die Eingabe informiert.
ausgabe_label = Label(fenster)

# Hier kann der Benutzer eine Eingabe machen
eingabefeld = Entry(fenster, bd=5, width=40)

ausgabe_button = Button(fenster, text="Klick me", command=button_action)
exit_button = Button(fenster, text="Beenden", command=fenster.quit)


# Nun fügen wir die Komponenten unserem Fenster hinzu
my_label.grid(row = 0, column = 0)
eingabefeld.grid(row = 0, column = 1)
ausgabe_button.grid(row = 1, column = 0)
exit_button.grid(row = 1, column = 1)
ausgabe_label.grid(row = 2, column = 0, columnspan = 2)

mainloop()

l12 = k*math.sqrt(100*75)
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

l + Nummer ist ein ganz schlechter Variablenname, ich habe mich gerade gewundert, wie man einer Zahl 112 einen Wert zuweisen kann?

Warum kannst Du die Berechnung nicht innerhalb von button_action durchführen?
Du kannst auf eingabefeld zugreifen, aber normalerweise braucht man für solche Probleme eine Klasse, die als Zustand den Wert `k` speichert.
blubbablas3
User
Beiträge: 10
Registriert: Sonntag 4. August 2019, 12:32

Danke für die Antwort. Die Variable heißt l12 für die gegenseitige Induktionen eines gekoppelten Schwingkreises.
Mein Code geht danach noch weiter und ich hätte gerne den Wert zur weiteren Verwendung.

Zu der Klasse: Soll ich die GUI in eine Klasse packen und mir k zurückgeben lassen?

Viele Grüße
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Ja, GUI in eine Klasse. Und bessere Variablennamen.
Benutzeravatar
__blackjack__
User
Beiträge: 14092
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@blubbablas3: Da fehlen die Importe und der Code lässt vermuten das alles aus `tkinter` per Sternchenimport in das Modul geholt wurde.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Alles was Funktionen und Methoden ausser Konstanten benötigen sollte als Argument(e) übergeben werden. `button_action()` benötigt also `eingabefeld` und `ausgabe_label` als Argumente. Das geht hier noch mit `functools.partial()` aber letztendlich braucht man für nicht-triviale GUI-Programme objectorientierte Programmierung.

`my` ist selten ein sinnvoller Namenszusatz weil der nichts aussagt. Solange es nicht auch so etwas wie `our_label` oder `their_label` gibt gegen die man das `my_label` abgrenzen muss. Darüber steht der Kommentar ``# Anweisungs-Label``. Wenn man Namen erklären muss, sollte man immer überlegen ob man nicht einen besseren Namen finden kann, bei dem man sich einen erklärenden Kommentar sparen kann. In diesem Fall beispielsweise sehr naheliegend einfach das was im Kommentar steht: `anweisungs_label`.

Faustregel für Kommentare: Nicht kommentieren *was* passiert, denn das steht da bereits als Code, sondern warum der Code das *so* macht. Sofern das nicht offensichtlich ist.

Das ``k = float(entry_text)`` in `button_action` macht Probleme. Wenn die Eingabe nicht in eine Gleitkommazahl umgewandet werden kann wird eine Ausnahme ausgelöst und die Bedingung im nachfolgenden ``if`` wird nie erreicht, denn wenn das ausgeführt wird ist schon garantiert das der Text nicht die leere Zeichenkette gewesen sein kann, denn dann wäre in der Zeile davor eine Ausnahme ausgelöst worden.

Ich würde auch von `k` als Namen abraten wenn man `kopplungsfaktor` meint.

Es würde sich hier anbieten mit einem `tkinter.DoubleVar`-Objekt zu arbeiten und das dem `Entry` und der `button_action()`-Funktion zu übergeben.

Zwischenstand:

Code: Alles auswählen

#!/usr/bin/env python3
import math
import tkinter as tk
from functools import partial


def button_action(kopplungsfaktor_var, ausgabe_label):
    kopplungsfaktor = None
    try:
        kopplungsfaktor = kopplungsfaktor_var.get()
    except tk.TclError:
        pass  # Variable not a float, `kopplungsfaktor` stays `None`.
    else:
        if not (0 < kopplungsfaktor < 1):
            kopplungsfaktor = None

    if kopplungsfaktor is None:
        ausgabe_label.config(text="Geben Sie bitte zuerst k (0<k<1) ein.")
    else:
        ausgabe_label.config(text=f"Kopplungsfaktor = {kopplungsfaktor}")


def main():
    fenster = tk.Tk()
    fenster.title("Eingabe: Kopplungsfaktor k.")

    kopplungsfaktor_var = tk.DoubleVar(value=0.5)

    anweisungs_label = tk.Label(
        fenster, text="Geben Sie den Kopplungsfaktor k ein: "
    )
    ausgabe_label = tk.Label(fenster)
    eingabefeld = tk.Entry(
        fenster, textvariable=kopplungsfaktor_var, bd=5, width=40
    )
    ausgabe_button = tk.Button(
        fenster,
        text="Klick me",
        command=partial(button_action, kopplungsfaktor_var, ausgabe_label),
    )
    exit_button = tk.Button(fenster, text="Beenden", command=fenster.quit)

    anweisungs_label.grid(row=0, column=0)
    eingabefeld.grid(row=0, column=1)
    ausgabe_button.grid(row=1, column=0)
    exit_button.grid(row=1, column=1)
    ausgabe_label.grid(row=2, column=0, columnspan=2)

    fenster.mainloop()
    #
    # TODO Needs exception handling.
    #
    kopplungsfaktor = kopplungsfaktor_var.get()
    print(kopplungsfaktor * math.sqrt(100 * 75))


if __name__ == "__main__":
    main()
`button_action()` ist als Name nicht gut weil der nichts darüber aussagt was da eigentlich passiert. Und es ist ungewöhnlich das nach dem GUI-Code noch welcher steht der mit Werten weiterarbeitet. Der Code sollte mindestens in einer Funktion stehen, damit man den auch ohne GUI mal testen oder auch regulär benutzen kann. Letztlich würde man das dann aber auch nicht nach dem Ende der GUI machen, sondern wie Sirius3 schon andeutete als Reaktion auf den Knopfdruck.
“It is easier to change the specification to fit the program than vice versa.” — Alan J. Perlis
blubbablas3
User
Beiträge: 10
Registriert: Sonntag 4. August 2019, 12:32

Ok. Vielen Dank für eure Hilfe.
Antworten