Seite 1 von 1

Entryfeld auslesen mit .get()

Verfasst: Mittwoch 23. September 2020, 14:32
von Kahnbein.Kai
Hallo,
ich versuche verzweifelt ein Entryfeld mit der Methode .get() auszulesen. Es klappt leider nicht.
Die Fehlermeldung:

Code: Alles auswählen

kai@Kai-Desktop:~/Dokumente/Python/Interface$ python3 bsp.py
Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 1705, in __call__
    return self.func(*args)
  File "bsp.py", line 9, in berechnung
    print(eingabe1.get())
AttributeError: 'NoneType' object has no attribute 'get'
Hier ist der Code

Code: Alles auswählen

import tkinter as tk
master = tk.Tk()
master.title("Dreisatz berechnen")


eingabe1 = tk.IntVar(master, 4)

def berechnung():
    print(eingabe1.get())

eingabe1 = tk.Entry(master, textvariable=eingabe1).grid(row=1,column=0)

tk.Button(master, text="Berechnung", command=berechnung).grid(row=3, column=0)

tk.mainloop()
Wenn ich die Zeile "print(eingabe1.get())" außerhalb der Funktion schreibe, wird die Zahl 4 richtig ausgeben. Warum funktioniert das nicht in Verbindung mit der Funktion ?

Gruß Kai

Re: Entryfeld auslesen mit .get()

Verfasst: Mittwoch 23. September 2020, 14:34
von Kahnbein.Kai
Ha, wie der Ochs vorm Berg, ich habe die Variable "Eingabe1" hinterher wieder überschrieben :(
Peinlich....

Wenn man den Variablennamen des Entryfeldes ändert klappt es :)



Kann also gelöscht werden :)

Re: Entryfeld auslesen mit .get()

Verfasst: Mittwoch 23. September 2020, 16:56
von __blackjack__
@Kahnbein.Kai: Den Namen an den das `Entry`-Objekt gebunden wird braucht man nicht ändern, das kann man ganz einfach an *gar keinen Namen* binden. Machst Du bei dem `Button`-Objekt ja auch nicht.

Das hat da auf Modulebene alles nix zu suchen und für jede nicht-triviale GUI braucht man mindestens eine eigene Klasse. Hier könnte man bis hier hin noch mit `funtools.partial()` auskommen, damit `berechne()` das `IntVar`-Objekt als Argument übergeben bekommt.

Namen nummerieren ist bäh.

Re: Entryfeld auslesen mit .get()

Verfasst: Mittwoch 23. September 2020, 17:50
von Sirius3
Also so:

Code: Alles auswählen

import tkinter as tk
from functools import partial

def berechnung(eingabe):
    print(eingabe.get())

def main():
    master = tk.Tk()
    master.title("Dreisatz berechnen")
    eingabe = tk.IntVar(master, 4)
    tk.Entry(master, textvariable=eingabe).grid(row=1, column=0)
    tk.Button(master, text="Berechnung", command=partial(berechnung, eingabe)).grid(row=2, column=0)
    master.mainloop()

if __name__ == "__main__":
    main()

Re: Entryfeld auslesen mit .get()

Verfasst: Freitag 25. September 2020, 05:50
von Kahnbein.Kai
Vielen Danke für die Aufklärung.

Ich sollte mir mal eine "leere" Pyrhondatei mit der der main() Klasse und der __init__ Anweisung speichern. Im Internet sind die Beispiele immer ohne zu finden. Das mit der partial Funktion ist so eine Sache, wenn man gut Programmieren kann, ist das sicherlich der schönere und besser weg. Als Anfänger jedoch würde ich ein eher aufgeschlüsselten Code bevorzugen, zwecks Nachvollziehbarkeit.

Gruß und schönes Wochenende
Kai

Re: Entryfeld auslesen mit .get()

Verfasst: Freitag 25. September 2020, 06:58
von Sirius3
Oft findet man halt nur Programmfragmente, die ein bestimmtes Problem lösen sollen. Da ist dann eine main-Funktion überflüssig, weil es in größeren Code eingebaut werden muss.
Nicht die partial-Funktion ist komplex, sondern Callback-Funktionen. Und jede andere Art der Parameterübergabe ist für Anfänger und Fortgeschrittene weniger nachvollziehbar.
Es sei denn, man verwendet eine Klasse und vermeidet so die Parameter ganz.

Re: Entryfeld auslesen mit .get()

Verfasst: Freitag 25. September 2020, 12:33
von __blackjack__
Um GUIs zu programmieren, oder allgemein irgend etwas das Rückruffunktionen verwendet, muss man entweder Closures oder Klassen verstanden haben. Falls man sich über Aufrufe hinweg was merken will/muss, dann sind es Klassen. Seit dem Python ``nonlocal`` kennt, gingen hier auch Closures, aber das habe ich noch nie irgendwo jemanden machen sehen, und es würde IMHO auch gegen „There should be one-- and preferably only one --obvious way to do it.“ verstossen.

Und Closures oder Klassen zu lernen ist IMHO auch nicht so wirklich eine Wahl denn man lernt beides besser wenn man auch das jeweils andere Konzept kennt und versteht wie man Klassen mit Closures umsetzen kann und Closures mit Klassen.

Re: Entryfeld auslesen mit .get()

Verfasst: Sonntag 27. September 2020, 16:39
von Kahnbein.Kai
ok, ab jetzt immer mit main Funktion ;)

Das Programm läuft soweit mit globalen Variablen. Ich möchte es mit lokalen Variablen (außer ausgabe1) zum laufen bekommen, das klappt leider nicht.
Das Ausgabenlabel wird nicht aktualisiert.

Hier ist der Code:

Code: Alles auswählen

import tkinter as tk

master = tk.Tk()
master.title("Dreisatz berechnen")


ausgabe1 = tk.IntVar()

def berechnung(e1,e2,e3,wahl):
    if wahl.get()== 1:
        ausgabe1.set((e3.get()*e2.get())/e1.get())
        print(e1.get())
    else:
        ausgabe1.set((e2.get()*e1.get())/e3.get())
    return ausgabe1

def main():

    wahl = tk.IntVar()
    eingabe1 = tk.IntVar(master,10)
    eingabe2 = tk.IntVar(master,100)
    eingabe3 = tk.IntVar(master,20)

    tk.Radiobutton(master, text="Proportional", padx = 20, variable=wahl,value=1).grid(row=0,column=0, columnspan=2)
    tk.Radiobutton(master, text="Antiproportional",padx = 20, variable=wahl, value=2).grid(row=0,column=2, columnspan=1)

    tk.Button(master, text="Berechnung", command=berechnung(eingabe1,eingabe2,eingabe3,wahl)).grid(row=3, column=0)   

    tk.Entry(master, textvariable=eingabe1).grid(row=1,column=0)
    tk.Label(master, text="=").grid(row=1,column=1)
    tk.Entry(master, textvariable=eingabe2).grid(row=1,column=2)

    tk.Entry(master, textvariable=eingabe3).grid(row=2,column=0)
    tk.Label(master, text="=").grid(row=2,column=1)
    tk.Label(master, textvariable=ausgabe1).grid(row=2, column=2)

    master.mainloop()
    
if __name__ == "__main__":
	main()
Hier ist ein Bild der Maske mit den verschiedenen Felder:
Bild

Gruß Kai

Re: Entryfeld auslesen mit .get()

Verfasst: Sonntag 27. September 2020, 16:47
von Sirius3
Ich hatte Dir doch schon geschrieben, dass Du functools.partial brauchst.

Code: Alles auswählen

import tkinter as tk
from functools import partial

def berechnung(ausgabe, e1, e2, e3, wahl):
    if wahl.get() == 1:
        ausgabe.set((e3.get()*e2.get())/e1.get())
        print(e1.get())
    else:
        ausgabe.set((e2.get()*e1.get())/e3.get())

def main():
    master = tk.Tk()
    master.title("Dreisatz berechnen")
    ausgabe = tk.IntVar(master)
    wahl = tk.IntVar(master)
    eingabe1 = tk.IntVar(master, 10)
    eingabe2 = tk.IntVar(master, 100)
    eingabe3 = tk.IntVar(master, 20)
    tk.Radiobutton(master, text="Proportional", padx=20, variable=wahl,value=1).grid(row=0,column=0, columnspan=2)
    tk.Radiobutton(master, text="Antiproportional",padx=20, variable=wahl, value=2).grid(row=0,column=2, columnspan=1)
    tk.Button(master, text="Berechnung", command=partial(berechnung, ausgabe, eingabe1,eingabe2,eingabe3,wahl)).grid(row=3, column=0)   
    tk.Entry(master, textvariable=eingabe1).grid(row=1,column=0)
    tk.Label(master, text="=").grid(row=1,column=1)
    tk.Entry(master, textvariable=eingabe2).grid(row=1,column=2)
    tk.Entry(master, textvariable=eingabe3).grid(row=2,column=0)
    tk.Label(master, text="=").grid(row=2,column=1)
    tk.Label(master, textvariable=ausgabe).grid(row=2, column=2)
    master.mainloop()
    
if __name__ == "__main__":
    main()

Re: Entryfeld auslesen mit .get()

Verfasst: Sonntag 27. September 2020, 17:04
von Kahnbein.Kai
Ok, super, jetzt klappt es.

Jetzt bin ich verwirrt. Warum bekommt die Funktion 'berechnung()' das 'IntVar' Argument nur mit partial übergeben ? Die Dokus die ich zu partial finde, beschreiben immer "fehlende" Argumente die man hinterher hinzufügen kann. Ich kann doch benötigten Argumente sofort übergeben.

Warum werden denn in Klassen Parameter ganz vermieden ? Die gibt es doch da auch, oder verstehe ich das falsch ?

Gruß Kai

Re: Entryfeld auslesen mit .get()

Verfasst: Sonntag 27. September 2020, 17:52
von Kahnbein.Kai
Ich habe es nochmal umgeschrieben mit einer Klasse.
Sieht echt besser aus, ihr habt recht.

Gruß Kai

Code: Alles auswählen

import tkinter as tk


class Dreisatz(tk.Tk):

    def __init__(self):
        super().__init__()
        self.eingabe1 = tk.IntVar(self)
        self.eingabe2 = tk.IntVar(self)
        self.eingabe3 = tk.IntVar(self)
        self.wahl = tk.IntVar(self)
        self.ausgabe1 = tk.IntVar(self)
    
 
        self.title("Dreisatz berechnen")

        tk.Radiobutton(self, text="Proportional", padx = 20, variable=self.wahl,value=1).grid(row=0,column=0)
        tk.Radiobutton(self, text="Antiproportional",padx = 20, variable=self.wahl, value=2).grid(row=0,column=2)

        tk.Button(self, text="Berechnung", command=self.berechnung).grid(row=3, column=0, columnspan = 3)   

        tk.Entry(self, textvariable=self.eingabe1).grid(row=1,column=0)
        tk.Label(self, text="=").grid(row=1,column=1)
        tk.Entry(self, textvariable=self.eingabe2).grid(row=1,column=2)

        tk.Entry(self, textvariable=self.eingabe3).grid(row=2,column=0)
        tk.Label(self, text="=").grid(row=2,column=1)
        tk.Label(self, textvariable=self.ausgabe1).grid(row=2, column=2)

    def berechnung(self):
        if self.wahl.get()== 1:
            self.ausgabe1.set((self.eingabe3.get()*self.eingabe2.get())/self.eingabe1.get())
        else:
            self.ausgabe1.set((self.eingabe2.get()*self.eingabe1.get())/self.eingabe3.get())
  
def main():
    master = Dreisatz()
    master.mainloop()
    
    
if __name__ == "__main__":
    main()

Re: Entryfeld auslesen mit .get()

Verfasst: Sonntag 27. September 2020, 17:59
von Sirius3
Callbacks brauchen eine Funktion ohne Parameter, `berechnung` hat aber 5 davon. Daher muß man mit partial eine Funktion definieren, deren 5 Parameter mit Werten vorbelegt sind.

Das ganze mit Klasse:

Code: Alles auswählen

import tkinter as tk

class Fenster:
    def __init__(self):
        master = tk.Tk()
        master.title("Dreisatz berechnen")
        self.master = master
        self.ausgabe = tk.IntVar(master)
        self.wahl = tk.IntVar(master)
        self.eingabe1 = tk.IntVar(master, 10)
        self.eingabe2 = tk.IntVar(master, 100)
        self.eingabe3 = tk.IntVar(master, 20)
        tk.Radiobutton(master, text="Proportional", padx=20, variable=self.wahl,value=1).grid(row=0, column=0, columnspan=2)
        tk.Radiobutton(master, text="Antiproportional", padx=20, variable=self.wahl, value=2).grid(row=0, column=2, columnspan=1)
        tk.Button(master, text="Berechnung", command=self.berechnung).grid(row=3, column=0)   
        tk.Entry(master, textvariable=self.eingabe1).grid(row=1, column=0)
        tk.Label(master, text="=").grid(row=1, column=1)
        tk.Entry(master, textvariable=self.eingabe2).grid(row=1, column=2)
        tk.Entry(master, textvariable=self.eingabe3).grid(row=2, column=0)
        tk.Label(master, text="=").grid(row=2, column=1)
        tk.Label(master, textvariable=self.ausgabe).grid(row=2, column=2)

    def mainloop():    
        self.master.mainloop()

    def berechnung(self):
        if self.wahl.get() == 1:
            self.ausgabe.set((self.eingabe3.get()*self.eingabe2.get())/self.eingabe1.get())
        else:
            self.ausgabe.set((self.eingabe2.get()*self.eingabe1.get())/self.eingabe3.get())

def main():
    fenster = Fenster()
    fenster.mainloop()

if __name__ == "__main__":
    main()

Re: Entryfeld auslesen mit .get()

Verfasst: Sonntag 27. September 2020, 18:10
von Kahnbein.Kai
Danke, ich glaube ich habe es jetzt ein wenig mehr verstanden. :)

Schönen Abend noch !