Probleme mit Variablen und tkinter

Fragen zu Tkinter.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Du hast recht set brauche ich gar nicht - nur kann ich nicht sagen warum es vorher nicht funktioniert hat ???? na -egal es geht auch ohne!
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo Ihr !!!

Habe mal weiter gemacht, doch bekomme ich eine große Ungenauigkeit bei der Berechnung. So wie ich das verstanden habe, liegt es am Auslesen der Daten und ich müsste das modul decimal verwenden !? Habe ich noch nicht so hinbekommen, doch zwei Schritte vor und manchmal auch drei zurück !!
Den Tip von schlangenbeschwörer habe ich auch noch nicht eingebaut, da ich bei grid () nicht immer pady bzw. padx angeben kann - oder ?? Diese Angaben summieren sich doch auf und die Tastenabstände würden nicht gleich bleiben ?! Ich hatte die Idee, die Werte in eine Tulpe oder Liste einzutragen und auszulesen - macht das Sinn ?

Code: Alles auswählen

# -*- coding: iso-8859-15 -*-
from Tkinter import *

class Rechner (Frame):
      
      def __init__(self, master=None):
            self.speicher = ""
            self.mspeicher = ""
            Frame.__init__(self, master,)
            self.pack()

           
            self.buttonsieben = Button(self, text="7",width=3, command=self.eingabesieben)
            self.buttonsieben.grid(row=7, column=1,padx=10)
            self.buttonacht = Button(self,text="8",width=3, command=self.eingabeacht)
            self.buttonacht.grid(row=7, column=2)
            self.buttonneun = Button(self, text="9",width=3, command=self.eingabeneun)
            self.buttonneun.grid(row=7, column=3,padx=10)
            self.buttonneun = Button(self, text="/",width=3, command=self.eingabedivi)
            self.buttonneun.grid(row=7, column=4)
            self.buttonloeschen = Button(self, text="C",width=3, command=self.loeschen)
            self.buttonloeschen.grid(row=7, column=5,padx=10)

            self.buttonvier = Button(self, text="4",width=3, command=self.eingabevier)
            self.buttonvier.grid(row=8, column=1,pady=10)
            self.buttonfuenf = Button(self, text="5",width=3, command=self.eingabefuenf)
            self.buttonfuenf.grid(row=8, column=2)
            self.buttonsechs = Button(self, text="6",width=3, command=self.eingabesechs)
            self.buttonsechs.grid(row=8, column=3,)
            self.buttonmulti = Button(self, text="X",width=3, command=self.eingabemulti)
            self.buttonmulti.grid(row=8, column=4)
            self.buttonprozent = Button(self, text="%",width=3, command=self.eingabeprozent)
            self.buttonprozent.grid(row=8, column=5,)

            self.buttoneins = Button(self, text="1",width=3, command=self.eingabeeins)
            self.buttoneins.grid(row=9, column=1)
            self.buttonzwei = Button(self, text="2",width=3, command=self.eingabezwei)
            self.buttonzwei.grid(row=9, column=2)
            self.buttondrei = Button(self, text="3",width=3, command=self.eingabedrei)
            self.buttondrei.grid(row=9, column=3)
            self.buttonminus = Button(self, text="-",width=3, command=self.eingabeminus)
            self.buttonminus.grid(row=9, column=4)
            self.buttonspeicher = Button(self, text="M",width=3, command=self.eingabemspeicher)
            self.buttonspeicher.grid(row=9, column=5)

            self.buttonnull = Button(self, text="0",width=3, command=self.eingabenull)
            self.buttonnull.grid(row=10, column=1,pady=10)
            self.buttonplusminus = Button(self, text="+/-",width=3, command=self.eingabevorzeichen)
            self.buttonplusminus.grid(row=10, column=2,)
            self.buttonkomma = Button(self, text=",",width=3, command=self.eingabekomma)
            self.buttonkomma.grid(row=10, column=3)
            self.buttonplus = Button(self, text="+",width=3, command=self.eingabeplus)
            self.buttonplus.grid(row=10, column=4)
            self.buttongleich = Button(self, text="=",width=3, command=self.eingabegleich)
            self.buttongleich.grid(row=10, column=5)

            self.ausgabe = Entry(self,width=29,justify="right",)
            self.ausgabe.grid(row=0, column=0,columnspan=6,pady=10)


      def eingabeeins(self):
            
            self.ausgabe.insert(50,"1",)

      def eingabezwei(self):
            
            self.ausgabe.insert(50,"2")
                  
      def eingabedrei(self):

            self.ausgabe.insert(50,"3")

      def eingabeminus(self):
      
            self.speicher = self.speicher + self.ausgabe.get() + "-"
            self.ausgabe.delete(0,END)
            
            
      def eingabemspeicher(self):

            if self.ausgabe.get() =="":
                  
                  self.speicher = self.speicher + self.mspeicher
                  
            if self.ausgabe.get() !="":
                  
                  self.mspeicher = self.ausgabe.get()
                  self.ausgabe.delete(0,END)
                  self.ausgabe.insert(50,"")
            
      def eingabenull(self):

            self.ausgabe.insert(50,"0")
            
      def eingabevorzeichen(self):

            self.vorzeichen = str(float (self.ausgabe.get()) * -1)
            self.ausgabe.delete(0,END)
            self.ausgabe.insert(50,self.vorzeichen)

            
      def eingabekomma(self):
      
           self.ausgabe.insert(50,".")
                        
      def eingabeplus(self):

            self.speicher = self.speicher + self.ausgabe.get()+ "+"
            self.ausgabe.delete(0,END)
            
      def eingabevier(self):
            
            self.ausgabe.insert(50,"4")

      def eingabefuenf(self):
            
            self.ausgabe.insert(50,"5")

      def eingabesechs(self):

            self.ausgabe.insert(50,"6")

      def eingabemulti(self):
         
            self.speicher = self.ausgabe.get()+ "*"
            self.ausgabe.delete(0,END)

      def eingabeprozent(self):

            self.speicher = self.ausgabe.get()
            self.speicher = (self.speicher + "/" + "100" + "*")
            self.ausgabe.delete(0,END)

      def eingabegleich(self):
            
            try:
                  
                  self.speicher = str(eval (self.speicher + self.ausgabe.get()))
                  self.ausgabe.delete(0,END)
                  self.ausgabe.insert(50,self.speicher)
                  self.speicher = ""
                  
            except:
                  
                  self.ausgabe.delete(0,END)
                  self.speicher = ""
                  self.ausgabe.insert(50,"E")
     
      def eingabesieben(self):
            
            self.ausgabe.insert(50,"7")

      def eingabeacht(self):
            
            self.ausgabe.insert(50,"8")

      def eingabeneun(self):
            
            self.ausgabe.insert(50,"9")

      def eingabedivi(self):
            
            self.speicher = self.speicher + self.ausgabe.get()+ "/"
            self.ausgabe.delete(0,END)

      def loeschen(self):

            self.ausgabe.delete(0,END)
            self.speicher = ""
            self.mspeicher = ""
     
       
root = Tk()
root.title('mudda`s Rechner 1.0')
root.config(cursor='crosshair')
Rechner(root).mainloop()
gruss frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

So wotte ich es mit einer schleife verkürzen, doch ich habe da so meine Probleme. Die Darstellung funktioniert nur bei insert fügt er immer den letzten Durchlauf der schleife ein - macht ja auch irgendwie Sinn - wie kann ich dieses Problem lösen ? Mit einem Zähler: a=a+1 oder so etwas in der Art ?

Code: Alles auswählen

# -*- coding: iso-8859-15 -*-
from Tkinter import *

class Rechner (Frame):
      
      def __init__(self, master=None):
            tastenlayout = [("7",3,7,1,10,0),("8",3,7,2,0,0),("9",3,7,3,10,0),
                               ("4",3,8,1,0,10),("5",3,8,2,0,0),("6",3,8,3,0,0),
                               ("1",3,9,1,0,0),("2",3,9,2,0,0),("3",3,9,3,0,0)]

            Frame.__init__(self, master,)
            self.pack()

            for text, width, row, column, padx, pady in tastenlayout:
                  
                  self.tasten = Button(self, text=text,width=width, command=lambda:self.ausgabe.insert(50,text))
                  self.tasten.grid(row=row, column=column, padx=padx, pady=pady)


                  self.ausgabe = Entry(self,width=29,justify="right",)
                  self.ausgabe.grid(row=0, column=0,columnspan=6,pady=10)


root = Tk()
root.title('mudda`s Rechner 1.0')
root.config(cursor='crosshair')
Rechner(root).mainloop()
gruss frank
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

Hi Frank,
Zeile 17 so umändern.

Code: Alles auswählen

self.tasten = Button(self, text=text,width=width,command=lambda self=self, t=text: self.ausgabe.insert(50,t))
dann müsste es gehen.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Danke !!!!

Ja so geht es - nur habe ich es nicht verstanden ?! das self =self konnte ich löschen und es geht trotzdem ? Kann mir das jemand erklären?


gruss und dank frank
BlackJack

Die freien Namen im ``lambda``-Ausdruck werden erst beim Aufruf ausgewertet, dass heisst erst beim Aufruf wird geschaut an was die Namen `self` und `t` in diesem Augenblick gebunden sind. `self` bleibt ja immer gleich, nur `t` wird in der Schleife immer an verschiedene Texte gebunden und wenn die `command`-Funktion aufgerufen wird, ist das `t` an das letzte Element vom Schleifendurchlauf gebunden.

Default-Argumente von Funktionen werden dagegen immer bei der Definition an die Namen gebunden.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Danke BlackJack !!!

So nun habe ich mir gedacht auch die Tasten (+,-,etc) wiederholen sich in ihrer Funktion und so müsste es wieder mit lambda funktionieren. Nur geht es nicht - liegt es am syntax oder ist es ein denkfehler ?

Code: Alles auswählen

# -*- coding: iso-8859-15 -*-
from Tkinter import *

class Rechner (Frame):
      
      def __init__(self, master=None):
            tastenlayout = [("7",3,7,1,10,0),("8",3,7,2,0,0),("9",3,7,3,10,0),("4",3,8,1,0,10),
                            ("5",3,8,2,0,0),("6",3,8,3,0,0),("1",3,9,1,0,0),("2",3,9,2,0,0),
                            ("3",3,9,3,0,0),("0",3,10,1,0,10),(",",3,10,3,0,0)]
            
            funktastlayout = [("/",3,7,4,0,0),("X",3,8,4,0,0,),("-",3,9,4,0,0),("+",3,10,4,0,0)]

            speicher=""

            Frame.__init__(self, master,)
            self.pack()

            for text, width, row, column, padx, pady in tastenlayout:
                  
                  self.tasten = Button(self, text=text,width=width, command=lambda t=text: self.ausgabe.insert(50,t))
                  self.tasten.grid(row=row, column=column, padx=padx, pady=pady)

            for text, width, row, column, padx, pady in funktastlayout:

                  
                  self.funktasten = Button(self, text=text,width=width, command=lambda speicher=speicher+self.ausgabe.get()+ text : self.ausgabe.delete(0,END))
                  self.funktasten.grid(row=row, column=column, padx=padx, pady=pady)

                
            
            self.ausgabe = Entry(self,width=29,justify="right",)
            self.ausgabe.grid(row=0, column=0,columnspan=6,pady=10)

     
                  
root = Tk()
root.title('mudda`s Rechner 1.0')
root.config(cursor='crosshair')
Rechner(root).mainloop()
gruss und dank frank
BlackJack

Wie schon gesagt werden die Default-Argumente ausgewertet wenn die Funktion definiert wird. Also das was Du dort an `speicher` bindest, wird in der Schleife schon ausgewertet. Davon abgesehen das `self.ausgabe` zu dem Zeitpunkt noch nicht existiert, dürfte das nicht der richtige Zeitpunkt sein.

Da ``lambda``-Ausdrücke auf einfache Ausdrücke beschränkt sind, musst Du hier mit einem sogenannten "Closure" arbeiten. Ungetestet:

Code: Alles auswählen

    def _make_operator_command(self, text):
        def operator_command():
            self.speicher += self.ausgabe.get() + text
            self.ausgabe.delete(0, END)
        return operator_command
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Danke !!!

Also für Doofe: Mein Programm "hängt" beim der Ausführung in den beiden Schleifen und beim Tastendruck beginnt die "Auswertung" ....?! Da self.ausgabe.get () erst nach dem Drücken der Taste bekannt ist, kann ich es auswerten ?! Vorhergehend habe ich es mit def eingabeminus(self) ausgewertet und somit war self.ausgabe.get() bekannt ?! Dein Tip ist ja sowas in der Art nur nicht für alle einzeln, sondern für +,- etc. in einem Vorgang ? - alles klar ? Der Befehl return wird innerhalb eines Körpers einer Funktion verwendet -- habe ich abgeschrieben... Ich rufe beim Drücken der Tasten die Funktion def operator_command auf und diese gibt mir die werte in die Schleife zurück ...?. Bei dem vorhergenden Programm habe ich das nicht gemacht - ging aber doch auch ?

gruss und dank frank
BlackJack

Ehrlich gesagt habe ich Deinen letzten Text nicht verstanden. :-(

Das `command`-Argument von `Button` will eine aufrufbare Funktion/Methode haben. Die Methode `_make_operator_command()` hat als Rückgabewert eine Funktion, nämlich eine Instanz von der inneren Funktion `operator_command()`. Diese kann man an das `command`-Argument eines Buttons binden. Die Funktion wird genau dann aufgerufen wenn man auf den Button klickt.

Innere Funktionen haben Zugriff auf die lokalen Namen des Aufrufs der umgebenen Funktion, dass heisst wenn man so einen Namen benutzt, bekommt man das Objekt an den der äussere Name gerade gebunden ist. Wenn man eine Instanz der inneren Funktion als Rückgabewert benutzt, nimmt diese den lokalen Namensraum des äusseren Aufrufs sozusagen mit.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Das geht mir bei Deinen Erklärungen auch so (soll nicht wertend sein, sondern mir fehlen die Fachbegriffe oder das nötige Hintergrundwissen) Ich komme aus der Sonderpädagogik, deswegen lerne ich immer über das Handeln z.B.: Man lernt das Autofahren indem man ein Auto fährt und nicht weil man es in der Theorie kann. Immer beides zusammen, deswegen auch meine "doofen" Fragen. In dem Wort begreifen steckt das Wort greifen. Erst mit dem Greifen nach etwas kann man es begreifen - hört sich gut an - blöde Pädagogen :-).

Trotzdem vielen Dank für Deine schnellen Antworten und ich versuche es weiter mal mit Lesen.

gruss und dank frank
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Stichwort: Closures

Ein par Beispiel zum letzen Post von BlackJack gibt es hier: [wiki]Closures richtig anwenden[/wiki]

Und eine ausführlich Erklärung hier: http://de.wikipedia.org/wiki/Closure
BlackJack

@kaytec: "Closures" sind auch ein klein wenig komplizierter. Aber wenn man sie erst einmal verstanden hat, dann lassen sie sich vor allem in der GUI-Programmierung verwenden um Callback-Funktionen zu erstellen, die komplexere Dinge anstellen können, als mit ``lambda`` möglich ist.

Zum Thema ausprobieren: Dazu eignet sich Python durch den interaktiven Interpretierer sehr gut. Man kann "live" mit den ganzen Objekten herumspielen. Ein weiteres beliebtes "Closure"-Beispiel ist eine Funktion, die Funktionen produziert, welche einen festen Wert zu einem Argument addieren:

Code: Alles auswählen

In [46]: def make_adder(number):
   ....:     def add(n):
   ....:         return number + n
   ....:     return add
   ....:

In [47]: add5 = make_adder(5)

In [48]: add5(0)
Out[48]: 5

In [49]: add5(10)
Out[49]: 15

In [50]: add5(42)
Out[50]: 47
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

hi,
hier mal dein Code wie es ein bisschen optimiert funktionieren könnte.
Dabei kannst auch gleich die unschlagbaren kombination von Tkinters layout Manager sehen.

link: http://paste.pocoo.org/show/1159/

Gruss
pyStyler
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo pystyler !!

Ja so einen gibt es schon im Forum, doch bei meinem wollte ich nicht, dass die Zeichen +,- etc. im Rechenvorgang zusehen sind, sondern es wie ein richtiger taschenrechener funktioniert.

gruss und dank frank
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

kaytec hat geschrieben:doch bei meinem wollte ich nicht, dass die Zeichen +,- etc. im Rechenvorgang zusehen sind, sondern es wie ein richtiger taschenrechener funktioniert.
Mein "richtiger Taschenrechner" Zeigt auch Rechenzeichen an - finde ich sehr praktisch, weil ich die Eingaben editieren kann.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo pystyler !!

Da hast Du recht - habe ja auch ihn gefunden bei meiner Suche nach einem Anstoss, doch ihn kopieren wäre ja nicht gerade eine Anforderung - code zu klauen ist ok, doch wollte ich es halt anders machen und dabei lernen. Es geht nicht um besser oder schlechter, sondern um den Spass an der Sache (intrinsiche Motivation).

Danke für Deine Links - gruss frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

So - habe es mal eingebaut! Es passiert nicht´s - bekomme aber auch keine Fehlermeldung. Das Entry - Feld wird auch nicht gelöscht ??

Code: Alles auswählen

 self.funktasten = Button(self, text=text,width=width, command=lambda text=text:self._make_operator_command)
                  self.funktasten.grid(row=row, column=column, padx=padx, pady=pady)

                
            
            self.ausgabe = Entry(self,width=29,justify="right",)
            self.ausgabe.grid(row=0, column=0,columnspan=6,pady=10)


              
      def _make_operator_command(self, text):
            
              def operator_command():
                  self.speicher += self.ausgabe.get() + text
                  self.ausgabe.delete(0, END)
              return operator_command

gruss und dank frank
BlackJack

Erst einmal brauchst Du natürlich das ``lambda`` nicht mehr. Die Funktion soll ja von der neuen Methode erzeugt werden. Und dazu musst Du die auch aufrufen ─ mit dem Text der eingefügt werden soll als Argument.

Code: Alles auswählen

taste = Button(..., command=self._make_operator_command(text))
Der Name `taste` braucht auch nicht an das `Rechner`-Objekt gebunden werden. Ausserdem ist Mehrzahl falsch, der Name ist ja immer nur an *einen* `Button` gebunden. In der Zifferntasten-Schleife ist es das gleiche.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Danke BlackJack !!!

Habe voher mal versucht die links über closures zu verstehen - ok hat nicht geklappt !!! :-) Durch Deine Hilfe geht es jetzt - super und danke

gruss frank
Antworten