Tkinter, String des Klassenobjekts aus Entry.get weitergeben

Fragen zu Tkinter.
Antworten
raibel
User
Beiträge: 30
Registriert: Mittwoch 15. November 2006, 22:03

Hallo alle zusammen! :D


Ich habe mir zum Üben das Bankkonto-Beispiel von http://www.wspiegel.de/pykurs/kurs_index.htm genommen und mit einer Tkinter Gui versehen.

Code: Alles auswählen

 # Bankkonto-Beispiel von: http://www.wspiegel.de/pykurs/kurs_index.htm
from Tkinter import *


class Bankkonto(object):
    
    def __init__(self, startbetrag, kontonr):
        self.kontostand=startbetrag
        self.kontonr = kontonr

    def einzahlung(self, betrag):
        self.kontostand = self.kontostand + betrag 

        
    def auszahlung(self, betrag):
        self.kontostand = self.kontostand - betrag
        
    def ueberweisung(self, betrag, konto):
        self.auszahlung(betrag)
        konto.einzahlung(betrag)
       

    def anzeigen(self):
        if self.kontostand >= 0:
            L.insert(END, str(self.kontonr)+"  " +  str(self.kontostand)+ "    H")
        else:
            L.insert(END, str(self.kontonr)+"  " +  str(self.kontostand)+ "    S")
        
    def transfer(self):
        self.tk1=Toplevel()
        self.tk1.geometry("400x400")
        
        self.l2=Label(self.tk1, text="Einzahlung")
        self.l2.pack()
        self.e=Entry(self.tk1, bg="white")
        self.e.pack()
        def einz():
            L.delete(0, END)
            self.einzahlung(int (self.e.get()))
            command=k_anzeige()
            self.tk1.destroy()
        self.but1=Button(self.tk1, text="OK", command=einz)
        self.but1.pack()
        
        self.l3=Label(self.tk1, text="Auszahlung")
        self.l3.pack()
        self.e1=Entry(self.tk1, bg="white")
        self.e1.pack()
        def ausz():
            L.delete(0, END)
            self.auszahlung(int (self.e1.get()))
            command=k_anzeige()
            self.tk1.destroy()
        self.but2=Button(self.tk1, text="OK", command=ausz)
        self.but2.pack()
        
        self.l4=Label(self.tk1, text="Ueberweisung")
        self.l4.pack()
        self.e2=Entry(self.tk1, bg="white")
        self.e2.pack()
        self.l5=Label(self.tk1,  text="auf Konto")
        self.l5.pack()
        self.e3=Entry(self.tk1, bg="white")
        self.e3.pack()
        def ueberw():
            L.delete(0, END)
            self.ueberweisung(int (self.e2.get()), self.e3.get())
            command=k_anzeige()
            self.tk1.destroy()
        self.but2=Button(self.tk1, text="OK", command=ueberw)
        self.but2.pack()


konto1=Bankkonto(200, "Konto_1")
konto2=Bankkonto(100, "Konto_2")

tk=Tk()
tk.geometry("600x600")
b=Button(text="Konto_1", command=konto1.transfer)
b.pack()
b1=Button(text="Konto_2", command=konto2.transfer)
b1.pack()
L=Listbox(height=5, width=30, bg='white')
L.pack()

def k_anzeige():
    konto1.anzeigen(), konto2.anzeigen()
command=k_anzeige()

tk.mainloop() 


und hier die Fehlermeldung:

Code: Alles auswählen

line 20, in ueberweisung
    konto.einzahlung(betrag)
AttributeError: 'str' object has no attribute 'einzahlung'


Mit dem Rechnen klappt alles. Im Editor geht es auch!
Wie bekomme ich den String aus e3.get() als Wert?

Ich habe leider im Forum und auch im Netz nichts gefunden! Oder hat es was mit StringVar zu tun? :K
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

"String -> Wert" geht zwar, aber so solltes du das nicht machen.
Du musst eine Funktion schreiben, die das macht. Sprich eine Funktion mit einem dict die zum String das Konto-Objekt liefert.
raibel
User
Beiträge: 30
Registriert: Mittwoch 15. November 2006, 22:03

Ja,Ja,Ja! Das war's! :P

Vielen Dank für den Denkanstoss!!!

Ich habe es erstmal so gelöst:

Code: Alles auswählen

 # Bankkonto-Beispiel von: http://www.wspiegel.de/pykurs/kurs_index.htm
from Tkinter import *


class Bankkonto(object):
    
    def __init__(self, startbetrag, kontonr):
        self.kontostand=startbetrag
        self.kontonr = kontonr

    def einzahlung(self, betrag):
        self.kontostand = self.kontostand + betrag 

        
    def auszahlung(self, betrag):
        self.kontostand = self.kontostand - betrag
        
    def ueberweisung(self, betrag, konto):
        self.auszahlung(betrag)
        konto.einzahlung(betrag)
       

    def anzeigen(self):
        if self.kontostand >= 0:
            L.insert(END, str(self.kontonr)+"     " +  str(self.kontostand)+ "    H")
        else:
            L.insert(END, str(self.kontonr)+"     " +  str(self.kontostand)+ "    S")
        
    def transfer(self):
        self.tk1=Toplevel()
        self.tk1.geometry("400x400")
        
        self.l2=Label(self.tk1, text="Einzahlung")
        self.l2.pack()
        self.e=Entry(self.tk1, bg="white")
        self.e.pack()
        def einz():
            L.delete(0, END)
            self.einzahlung(int (self.e.get()))
            command=k_anzeige()
            self.tk1.destroy()
        self.but1=Button(self.tk1, text="OK", command=einz)
        self.but1.pack()
        
        self.l3=Label(self.tk1, text="Auszahlung")
        self.l3.pack()
        self.e1=Entry(self.tk1, bg="white")
        self.e1.pack()
        def ausz():
            L.delete(0, END)
            self.auszahlung(int (self.e1.get()))
            command=k_anzeige()
            self.tk1.destroy()
        self.but2=Button(self.tk1, text="OK", command=ausz)
        self.but2.pack()
        
        self.l4=Label(self.tk1, text="Ueberweisung")
        self.l4.pack()
        self.e2=Entry(self.tk1, bg="white")
        self.e2.pack()
        self.l5=Label(self.tk1,  text="auf Konto")
        self.l5.pack()
        self.e3=Entry(self.tk1, bg="white")
        self.e3.pack()
        def ueberw():
            L.delete(0, END)
            self.ueberweisung(int (self.e2.get()), d.get(self.e3.get()))
            command=k_anzeige()
            self.tk1.destroy()
        self.but2=Button(self.tk1, text="OK", command=ueberw)
        self.but2.pack()


d={}
d['konto1'] = Bankkonto (200, "Konto_1")
d['konto2'] = Bankkonto (100, "Konto_2")

tk=Tk()
tk.geometry("600x600")
b=Button(text="Konto_1", command= d.get('konto1').transfer)
b.pack()
b1=Button(text="Konto_2", command=d.get('konto2').transfer)
b1.pack()
L=Listbox(height=5, width=30, bg='white')
L.pack()

def k_anzeige():
    d.get('konto1').anzeigen(), d.get('konto2').anzeigen()
command=k_anzeige()

tk.mainloop() 

Noch ne Frage: Wie bekomme ich das Minuszeichen weg, wenn das Konto ins Soll geht? Der Soll-Betrag könnte dann auch rot werden.

Ansonsten > dies ist mein erstes Programm und ich bin über jede Art von Verbesserungsvorschlägen (keine * Importe) dankbar. So lernt man dazu!
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

1) Lass die *-Importe (doch ehrlich!) :wink:
2) Zu deiner Frage: abs(-1) = 1

Edit:

Was mir bei kurzem Überfliegen noch aufgefallen ist. Aus

Code: Alles auswählen

str(self.kontonr)+"     " +  str(self.kontostand)+ "    H"
kannst du auch

Code: Alles auswählen

 "%d     %f" % (self.kontonr, self.kontostand)
machen.

Und Variablen in einer Klasse "Bankkonto" "kontostand" zu nennen ist etwas redundant. "stand" reicht vollkommen aus, da du dich ja in dem Kontext des Kontos bewegst.

Allgemein solltest du dir mal Gedanken über deine Namensgebung machen: "l1" sagt einfach nichts aus. Du musst auch nicht alle Widgets an einen Namen binden, wenn du sie später nicht mehr direkt ansprechen musst (Stichwort: transfer-Methode).

Und man kann natürlich den letzten Teil noch ein wenig verallgemeinern:

Code: Alles auswählen

konten = [Bankkonto (200, "Konto_1") ,
               Bankkonto (100, "Konto_2")]

tk=Tk() 
tk.geometry("600x600") #so absolute angaben sind natuerlich auch nicht schoen!

for konto in konten:
    Button(text=konto.kontonr command=konto.transfer).pack()
raibel
User
Beiträge: 30
Registriert: Mittwoch 15. November 2006, 22:03

Hallo EyDu,

und Danke!

* Importe sind raus. abs war auch kein Problem.

Doch der Modulo-Operator hat's mir angetan. Schöner Name und schöne Funktionen.
Allerdings habe ich ziemlich lange gebraucht um etwas über die Bedeutung der Zusatzbuchstaben zu finden:
http://docs.python.org/lib/typesseq-strings.html
http://www.pasteur.fr/recherche/unites/ ... 06s02.html

Schade das man die "field width" vom zweiten Wert nicht auf den Anfang vom ersten Wert beziehen kann. Oder doch?
Man könnte dann viel einfacher den Abstand vom zweiten Wert setzen. Oder benutzt man dann eher eine MultiListbox?

Ich habe noch die Buttons für den Funktionsaufruf der einzelnen Konten im Startfenster durch ein Maus-Event ersetzt. Sieht schöner aus, aber die Listboxeinträge müssen 2x angeklickt werden.

Den Rest deiner Vorschläge werde ich noch bearbeiten!

Der Stand der Dinge:

Code: Alles auswählen

 #Klasse Bankkonto von: http://www.wspiegel.de/pykurs/kurs_index.htm
import Tkinter as tk
import tkMessageBox 

class Bankkonto(object):

    
    def __init__(self, startbetrag, kontonr):
        self.stand=startbetrag
        self.kontonr = kontonr

    def einzahlung(self, betrag):
        self.stand = self.stand + betrag 
        
    def auszahlung(self, betrag):
        self.stand = self.stand - betrag

    def ueberweisung(self, betrag, konto):
        self.auszahlung(betrag)
        konto.einzahlung(betrag)
       

    def anzeigen(self):
        L.bind("<Double-Button-1>", self.klick)
        
        if self.stand >= 0:
            L.insert(tk.END, "%-37d%.2f" % (self.kontonr, self.stand) + "H")
        else:
            L.insert(tk.END, "%d%27.2f" % (self.kontonr, self.stand) + "S")
        
    def klick(self, event=tk.NONE):
        if L.get("active")==L.get(1):
            d.get('11').transfer()
        if L.get("active")==L.get(2):
            d.get('22').transfer()

    def transfer(self):
        self.tk1=tk.Toplevel()
        self.l2=tk.Label(self.tk1, text="Einzahlung")
        self.l2.pack()
        self.e=tk.Entry(self.tk1, bg="white")
        self.e.pack()
        def einz():
            L.delete(0, tk.END)
            self.einzahlung(int (self.e.get()))
            command=k_anzeige()
            self.tk1.destroy()
        self.but1=tk.Button(self.tk1, text="OK", command=einz)
        self.but1.pack()
        
        self.l3=tk.Label(self.tk1, text="Auszahlung")
        self.l3.pack()
        self.e1=tk.Entry(self.tk1, bg="white")
        self.e1.pack()
        def ausz():
            L.delete(0, tk.END)
            self.auszahlung(int (self.e1.get()))
            command=k_anzeige()
            self.tk1.destroy()
        self.but2=tk.Button(self.tk1, text="OK", command=ausz)
        self.but2.pack()
        
        self.l4=tk.Label(self.tk1, text="Ueberweisung")
        self.l4.pack()
        self.e2=tk.Entry(self.tk1, bg="white")
        self.e2.pack()
        self.l5=tk.Label(self.tk1,  text="auf Konto")
        self.l5.pack()
        self.e3=tk.Entry(self.tk1, bg="white")
        self.e3.pack()
        def ueberw():
            L.delete(0, tk.END)
            self.ueberweisung(int (self.e2.get()), d.get(self.e3.get()))
            command=k_anzeige()
            self.tk1.destroy()
        self.but2=tk.Button(self.tk1, text="OK", command=ueberw)
        self.but2.pack()


d={}
d['11'] = Bankkonto (200, 11)
d['22'] = Bankkonto (100, 22)

root=tk.Tk()
L=tk.Listbox(height=5, width=30, bg='white', selectmode=tk.SINGLE)
L.pack()

m=tkMessageBox.showinfo("Hinweis","Kontoeintraege doppelt anklicken")

def k_anzeige():
    L.insert (tk.END, "%s%20s" % ("Konto"," Saldo"))
    d.get('11').anzeigen(), d.get('22').anzeigen()
command=k_anzeige()

root.mainloop() 
Gut so?
raibel
User
Beiträge: 30
Registriert: Mittwoch 15. November 2006, 22:03

Hallo! :)

Puuuhhh. Das war jetzt wrklich schwer (für mich). Eure Anregungen haben mich echt inspiriert! :D

Um eine möglichst komprimierte Lösung zu bekommen, habe ich jetzt die Buttonbeschriftung quasi als Listboxersatz benutzt.
Ich hatte aber echt Probleme mit dem dadurch enstandenen Doppelaufbau der Button-Widgets im Hauptfenster. Tja, Anfänger (Namesräume = global, local). :?

Fragen:

1) Ist die Lösung mit der Frames-Klasse so o.k.?
2) Warum erscheint das '33'er Konto in der Mitte und nicht unten?
3) Wie kann ich den Code noch weiter verkürzen und verbessern?

Und der Stand der Dinge:

Code: Alles auswählen

# bis Zeile-13 von: http://www.wspiegel.de/pykurs/kurs_index.htm
import Tkinter as tk

class Bankkonto(object):
    def __init__(self, startbetrag, kontonr):
        self.stand = float(startbetrag)
        self.kontonr = kontonr

    def einzahlung(self, betrag):
        self.stand = self.stand + betrag
       
    def auszahlung(self, betrag):
        self.stand = self.stand - betrag
        
    def ueberweisung(self, betrag, konto):
        self.auszahlung(betrag)
        konto.einzahlung(betrag)

    def transfer(self):
        self.tk1 = tk.Toplevel()
        tk.Label(self.tk1, fg='red', 
                 text="Konto Nr. =" + str(self.kontonr) + "=").grid()
        tk.Label(self.tk1, text = "Einzahlung").grid()
        self.e = tk.Entry(self.tk1, bg="white")
        self.e.grid()
        def einz():
            self.einzahlung(float(self.e.get()))
            frm.de_stroy()
            self.tk1.destroy()
        tk.Button(self.tk1, text = "OK", command = einz).grid()
       
        tk.Label(self.tk1, text = "Auszahlung").grid()
        self.e1 = tk.Entry(self.tk1, bg = "white")
        self.e1.grid()
        def ausz():
            self.auszahlung(float(self.e1.get()))
            frm.de_stroy()
            self.tk1.destroy()
        tk.Button(self.tk1, text = "OK", command = ausz).grid()
       
        tk.Label(self.tk1, text = "Ueberweisung").grid()
        self.e2=tk.Entry(self.tk1, bg = "white")
        self.e2.grid()
        tk.Label(self.tk1,  text = "auf Konto").grid()
        self.e3=tk.Entry(self.tk1, bg = "white")
        self.e3.grid()
        def ueberw():
            self.ueberweisung(float (self.e2.get()), konten.get(self.e3.get()))
            frm.de_stroy()
            self.tk1.destroy()
        tk.Button(self.tk1, text = "OK", command = ueberw).grid()

konten =   {'11': Bankkonto (148.12, 11), 
                    '22': Bankkonto (217.98, 22), 
                        '33': Bankkonto (-99.28, 33)}
root = tk.Tk()
tk.Label(text = "%-30s%13s" % ("Konto","Saldo")).grid()

class Frames():
    def fra_me(self):
        self.frame=tk.Frame()
        self.frame.grid()
        self.k_anzeige()
    def k_anzeige(self):
        for key, value in konten.items():
            if value.stand  >=0:
                tk.Button(self.frame, bg='white', text = "%d%38.2f" % 
                        (value.kontonr, abs(value.stand)) +"H", command = value.transfer).grid()
            else:
                tk.Button(self.frame, bg='white', fg='red', text = "%d%38.2f" % 
                        (value.kontonr, abs(value.stand)) + "S", command = value.transfer).grid()

    def de_stroy(self):
        self.frame.destroy()
        self.fra_me()

frm = Frames()
frm.fra_me()

root.mainloop()
Antworten