Einfacher Tachenrechner mit Tkinter

Fragen zu Tkinter.
Antworten
Sykes
User
Beiträge: 2
Registriert: Donnerstag 28. April 2016, 19:15

Hallo! ;)
Ich bin sehr neu in der Python Welt, bekomme aber schon einfach Programme zum laufen. Nur hierbei verzeifle ich.

Es geht eigentlich nur darum, dass sich ein Fenster öffnen soll indem ein Knopf "Addieren" ist und jedes mal wenn man diesen Knopf drückt, soll sich der Wert von x um 1 erhöhen. Das klappt aber leider nur beim ersten mal. Danach bleibt der Wert für x auf 1. Daraus schließe ich das die Return Funktion den x Wert nicht richtig zurück gibt...

Ich bin mir auch nicht so ganz sicher was dieser Lambda Opperator eigentlich macht, ich habe da ein Beispiel im Internet gefunden und der hat wenigstens etwas verbesserung in das Programm gebracht. :D

Ich hoffe mir kann da jemand helfen! :)

Viele Grüße und Danke im Vorraus!

Code: Alles auswählen


from tkinter import*

x=0

Fenster = Tk()

def addieren(x):
    x=x+1
    print(x)
    return(x)



Addierer = Button(Fenster, text="Addieren", command= lambda: addieren(x))
Addierer.pack()

Fenster.geometry("400x300")

Fenster.mainloop()
BlackJack

@Sykes: Wohin sollte das ``return`` den Wert auch zurückgeben? Die Funktion wird von der Tk-Hauptschleife aufgerufen wenn der Benutzer die Schaltfläche drückt. Diese Schleife erwartet da keinen Rückgabewert und der Code wüsste damit ja auch gar nichts anzufangen.

Das Hochzählen funktioniert übrigens jedes mal. Die Funktion bekommt allerdings jedes mal den Wert vom `x` auf Modulebene übergeben, also die 0 die sich nie ändert. Und die wird an das Argument `x` in der Funktion gebunden. Das `x` in der Funktion hat nichts mit dem `x` auf Modulebene zu tun.

Auf Modulebene sollten keine Variablen stehen. Da gehören nur Definitionen von Konstanten, Funktionen, und Klassen hin. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Apropos Namen: Schau mal in den Style Guide for Python Code was die Schreibweise von Namen angeht.

Die Lösung wäre das ordentlich mit objektorientierter Programmierung (OOP) zu lösen. Da kommt man bei GUI-Programmierung nicht drum herum. Da OOP *und* ereignisbasierte Programmierung bei GUIs zusammen vielleicht ein bisschen viel neuer Stoff ist, könnte man auch erst einmal OOP ohne GUI lernen.

``lambda`` definiert eine anonyme Funktion. Du könntest stattdessen auch eine Funktion mit einem Namen mit ``def`` definieren und die dann als `command` übergeben.
Sykes
User
Beiträge: 2
Registriert: Donnerstag 28. April 2016, 19:15

Das x aus der def sollte eigentlich direkt in die (wie du sie genannt hast) Modul ebene übergeben werden. (dazu das return)
Sozusagen das alte x (was vorher null war) mit einer 1 überschreiben. Im nächsten durchlauf sollte sich die def dann die 1 holen und ne 2 draußen machen... und so weiter.

Dass das eine x mit dem anderen nichts zutun hat habe ich bereits gelernt, aber um nicht zu verwirren habe ich einfach identische Namen gewählt.

Was du mit OOP meinst verstehe ich nicht wirklich. Ich habe natürlich schonmal davon gehört, aber ich dachte das dieses Problem doch auch einfacher zu lösen sein müsste und ich um dieses wohl sehr komplizierte Thema ersteinmal drum herum komme...
BlackJack

@Sykes: So funktioniert das mit Funktionen und ``return`` nicht. ``return`` gibt den Wert zum Aufrufer der Funktion zurück. Es wäre auch wirklich ungünstig wenn jede Funktion ihre Rückgabewerte im Modul abladen würde.

Es ist IMHO eher verwirrend das Du für beides den gleichen Namen gewählt hast. Ansonsten wäre Dir nämlich schnell aufgefallen dass das so nicht funkionieren kann. Wenn das auf Modulebene beispielsweise `i` heissen würde, woher sollte ein ``return x`` dann wissen, dass dieser Wert an den Namen `i` gehen soll, selbst wenn ``return`` so funktionieren würde, wie Du das gehofft hast?

Mit OOP meine ich das was man unter objektorientierter Programmierung halt versteht. In Python wären das dann Klassen um eigene Arten von Objekten zu erstellen. Es ist an sich nicht komplizierter als das anders zu lösen, auf lange Sicht eher einfacher, darum macht man das ja.

Das was Du vom Effekt her in dem Beispiel erreichen wolltest, das bei jedem Druck auf die Schaltfläche eine höhere Zahl ausgegeben wird, kann man noch sauber ohne OOP erreichen, aber auch nur weil es mit `itertools.count()` bereits ein fertiges Objekt dafür gibt. Wenn man den gleichen Wert mehrfach abfragen wollte, müsste man schon auf einen eigenen Datentyp zurückgreifen.

Code: Alles auswählen

import tkinter as tk
from itertools import count


def main():
    root = tk.Tk()
    numbers = count(1)
    tk.Button(
        root, text='Hochzählen', command=lambda: print(next(numbers))
    ).pack()
    root.mainloop()


if __name__ == '__main__':
    main()
Antworten