Erste GUI Programmierung

Fragen zu Tkinter.
Antworten
Bindl
User
Beiträge: 70
Registriert: Donnerstag 27. Oktober 2016, 11:48

Hallo zusammen,
wir müssen an unserer Hochschule bei einem Planspiel immer mal wieder berechnen wieviele Zutaten wir anhand unserer zu produzierenden Menge einzukaufen haben. Wir produzieren Pizzen.
Da ich keine Lust habe dies immer per Hand zu machen habe ich mir eine Python Programm geschrieben und nun möchte mal das ganze nicht mehr mit IDLE machen, also versuche ich mich an der GUI Programmierung.

Wenn ich das ganze ausführe gibt er mir den Error zurück das teig1 nicht definiert ist. Jedoch definiere ich ja in der Funktion magerita erst als 0 und gebe teig1 dann an die Funktion zutaten zurück (return) und möchte diese teig1-6 dann zu teig aussummieren.

Kann mir jmd. helfen?

[codebox=python file=Unbenannt.txt]from tkinter import *

fenster = Tk()
fenster.title("Test")
fenster.geometry("500x500")

# Verschachtelte Funktionen
def zutaten():
teig=sosse=gouda=salami=mozza=koch=ananas=lachs=spinat=hart=gorg=emmen=cham=pep=0
def magerita():
teig1=sosse1=gouda1=0
a = (float(eingabe1.get())*100)/1000
b = (float(eingabe1.get())*100)/1000
c = (float(eingabe1.get())*150)/1000
teig1+=a
sosse1+=b
gouda1+=c
return teig1,sosse1,gouda1
def salami():
teig2=sosse2=gouda2=salami1=0
a = (float(eingabe2.get())*100)/1000
b = (float(eingabe2.get())*50)/1000
c = (float(eingabe2.get())*150)/1000
d = (float(eingabe2.get())*50)/1000
teig2+=a
sosse2+=b
gouda2+=c
salami1+=d
return teig2,sosse2,gouda2,salami1
def hawaii():
teig3=sosse3=mozza1=koch1=ananas1=0
a = (float(eingabe3.get())*100)/1000
b = (float(eingabe3.get())*50)/1000
c = (float(eingabe3.get())*100)/1000
d = (float(eingabe3.get())*50)/1000
e = (float(eingabe3.get())*50)/1000
teig3+=a
sosse3+=b
mozza1+=c
koch1+=d
ananas1+=e
return teig3,sosse3,mozza1,koch1,ananas1
def lachs():
teig4=sosse4=mozza2=lachs1=spinat1=0
a = (float(eingabe4.get())*100)/1000
b = (float(eingabe4.get())*50)/1000
c = (float(eingabe4.get())*100)/1000
d = (float(eingabe4.get())*50)/1000
e = (float(eingabe4.get())*50)/1000
teig4+=a
sosse4+=b
mozza2+=c
lachs1+=d
spinat1+=e
return teig4,sosse4,mozza2,lachs1,spinat1
def kaese():
teig5=sosse5=mozza3=hart1=gorg1=emmen1=0
a = (float(eingabe5.get())*100)/1000
b = (float(eingabe5.get())*50)/1000
c = (float(eingabe5.get())*50)/1000
d = (float(eingabe5.get())*50)/1000
e = (float(eingabe5.get())*50)/1000
f = (float(eingabe5.get())*50)/1000
teig5+=a
sosse5+=b
mozza3+=c
hart1+=d
gorg1+=e
emmen1+=f
return teig5,sosse5,mozza3,hart1,gorg1,emmen1
def speziale():
teig6=sosse6=mozza4=salami2=cham1=koch2=pep1=0
a = (float(eingabe6.get())*100)/1000
b = (float(eingabe6.get())*50)/1000
c = (float(eingabe6.get())*100)/1000
d = (float(eingabe6.get())*25)/1000
e = (float(eingabe6.get())*25)/1000
f = (float(eingabe6.get())*25)/1000
g = (float(eingabe6.get())*25)/1000
teig6+=a
sosse6+=b
mozza4+=c
salami2+=d
cham1+=e
koch2+=f
pep1+=g
return teig6,sosse6,mozza4,salami2,cham1,koch1,pep1

teig=teig1+teig2+teig3+teig4+teig5+teig6
sosse=sosse1+sosse2+sosse3+sosse4+sosse5+sosse6
gouda=gouda1+gouda2
salami=salami1+salami2
mozza=mozza1+mozza2+mozza3+mozza4
koch=koch1+koch2
ananas,lachs,spinat,hart,gorg,emmen,cham,pep=ananas1,lachs1,spinat1,hart1,gorg1,emmen1,cham1,pep1

#Ausgabe
label.configure(text="Sie brauchen folgende Zutaten:\nTeig: {0} kg\nTomatensoße: {1} kg\nGouda: {2} kg\nSalami: {3} kg\nMozarella: {4} kg\nKochschinken: {5} kg\nAnanas: {6} kg\nLachs: {7} kg\nBlattspinat: {8} kg\nHartkäse: {9} kg\nGorgonzola: {10} kg\nEmmentaler {11} kg\nChampignons: {12} kg\nPeroni-Salami: {13} kg".format(teig,sosse,gouda,salami,mozza,koch,ananas,lachs,spinat,hart,gorg,emmen,cham,pep))


# Bezeichnungen der Eingabefenster
label1 = Label(fenster,text="Magerita").grid(row=0)
label2 = Label(fenster,text="Salami").grid(row=1)
label3 = Label(fenster,text="Hawaii").grid(row=2)
label4 = Label(fenster,text="Lachs Spinat").grid(row=3)
label5 = Label(fenster,text="Käse").grid(row=4)
label6 = Label(fenster,text="Speziale").grid(row=5)

# Eingabefenster
eingabe1 = Entry(fenster).grid(row=0, column=1)
eingabe2 = Entry(fenster).grid(row=1, column=1)
eingabe3 = Entry(fenster).grid(row=2, column=1)
eingabe4 = Entry(fenster).grid(row=3, column=1)
eingabe5 = Entry(fenster).grid(row=4, column=1)
eingabe6 = Entry(fenster).grid(row=5, column=1)

# Button zur Ausgabe
knopf = Button(fenster, text="Fertig",command=zutaten).grid(row=6, column=1)

mainloop()
[/code]

Danke schonmal für die Hilfe im voraus
Zuletzt geändert von Anonymous am Freitag 21. April 2017, 18:09, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@Bindl: Ich denke da kann man nicht helfen und das lohnt sich auch nicht. Das Programm wäre als Konsolenanwendung schon schlecht strukturiert, also eigentlich ist es das ja gar nicht, und als GUI-Anwendung funktioniert das *so* überhaupt nicht.

Zum Fehler: In der Funktion `magerita` wird `teig1` definiert, aber das existiert nur innerhalb des Funktionsaufrufs. Wenn die Funktion ausgeführt wurde, verschwindet der lokale Name innerhalb der Funktion. Ausserhalb der Funktion gibt es den nicht. Du gibst den *Wert* an den Aufrufer zurück. Also wenn die Funktion den auch mal irgend wo aufgerufen werden würde, dann würde das zumindest passieren. Die ganzen ”Pizzafunktionen” werden aber nirgends aufgerufen.

Die ”Pizzafunktionen” sollten aber auch gar keine Funktionen sein. Du hast da unglaublich viel an *Daten* in mehr oder weniger statischen Code geschrieben. Diese ganze durchnummerierten Namen und auch die `a`, `b`, `c`, … Namen sind alle Warnzeichen das hier was falsch läuft und eigentlich Datenstrukturen verwendet werden sollten und dann generische Funktionen. Zum Beispiel wäre eine Datenstruktur für eine Pizza sinnvoll die den Namen, die Zutaten, und die Mengen pro Pizza als Daten enthält. Dann kann man *eine* Funktion schreiben die so eine Pizzabeschreibung und eine Anzahl bekommt und daraus dann, auch wieder als Datenstruktur, die Gesamtmengen liefert. Wenn man das hat, kann man eine Funktion schreiben die zwei Zutaten”warenkörbe” bekommt und die zusammenrechnet. Wenn man das hat, kann man eine Funktion schreiben die eine Sequenz von Pizzabeschreibungen bekommt und zum Beispiel eine Abbildung „Pizzaname“ → Anzahl und in einer Schleife die Gesamtmenge über alle Pizzaarten ausrechnet.

Wenn man das hat, kann man sich mit objektorientierter Programmierung (OOP) beschäftigen, denn die braucht man für nicht-triviale GUI-Programmierung sowieso, und kann überlegen was von den Datenstrukturen sinnvoll in Objekte gekapselt werden kann. Dabei auch an die Interaktion mit der Python-Syntax denken. Statt einer Funktion zwei Warenkörbe zusammen zu rechnen, könnte man Beispielweise auch die ”magische” Methode für den ``+``-Operator implementieren und die Objekte dann einfach addieren als wären es Zahlen. Oder man kann die `sum()`-Funktion verwenden um eine Sequenz oder ein „iterable“ von Warenkörben zu summieren.

Verschachtelte Funktionen sollte man vermeiden solange es nicht Closures sind oder wirklich sehr kleine Hilfsfunktionen die in der Funktion als Argument bei einem Aufruf übergeben werden aber zu lang für ``lambda``-Ausdrücke sind. Das macht den Code sonst nur unübersichtlich und schwer zu testen, weil man an die inneren Funktionen ja nicht heran kommt um sie separat zu testen.
BlackJack

Mal so als Ansatz mit den Rezepten und dem Einkaufszettel als Wörterbücher:

Code: Alles auswählen

from collections import defaultdict

RECIPES = {
    'Magerita': {
        'Teig': 100,
        'Sosse': 100,
        'Gouda': 150,
    },
    'Salami': {
        'Teig': 100,
        'Sosse': 50,
        'Gouda': 150,
        'Salami': 50,
    },
    'Hawaii': {
        'Teig': 100,
        'Sosse': 50,
        'Mozarella': 100,
        'Kochschinken': 50,
        'Ananas': 50,
    },
}


def calculate_one(recipe, count):
    return dict(
        (name, amount * count / 1000) for name, amount in recipe.items()
    )


def calculate_many(name2count):
    ingredient2amount = defaultdict(float)
    for recipe_name, count in name2count.items():
        for name, amount in calculate_one(RECIPES[recipe_name], count).items():
            ingredient2amount[name] += amount
    return ingredient2amount


def ingredients_as_string(ingredient2amount):
    result = ['Sie brauchen folgende Zutaten:']
    result.extend(
        '{0}: {1:.2f} kg'.format(name, amount)
        for name, amount in sorted(ingredient2amount.items())
    )
    return '\n'.join(result)


def ask_pizza_counts():
    name2count = dict()
    for name in sorted(RECIPES):
        name2count[name] = float(input('Wie viele {0}: '.format(name)))
    return name2count


def main():
    print(ingredients_as_string(calculate_many(ask_pizza_counts())))


if __name__ == '__main__':
    main()
Ich habe nur die ersten drei Pizzaarten übernommen. Füge die restlichen mal hinzu und vergleiche das mit dem Aufwand den in Deinem Code beim zufügen einer weiteren Pizzaart hast und wie verteilt über den gesamten Code Du die Änderungen machen musst.

Testlauf:
[codebox=text file=Unbenannt.txt]Wie viele Hawaii: 1
Wie viele Magerita: 3
Wie viele Salami: 2
Sie brauchen folgende Zutaten:
Ananas: 0.05 kg
Gouda: 0.75 kg
Kochschinken: 0.05 kg
Mozarella: 0.10 kg
Salami: 0.10 kg
Sosse: 0.45 kg
Teig: 0.60 kg[/code]
Antworten