Random Ergebnis als Labeltext anzeigen

Fragen zu Tkinter.
Antworten
NilsV
User
Beiträge: 30
Registriert: Dienstag 17. August 2010, 12:35

Hallo,

ich habe ein einfaches Gui mit einem Label und einem Button. Jedes mal wenn ich auf den Button drücke soll per Zufall entweder Kreuz, Pik, Herz oder Karo als Labeltext angezeigt werden.

Dafür habe ich eine Funktion zufall() geschrieben, die Ihr Ergebnis als Beschriftung für das Label ausgibt. Diese Funktion sollte jedes mal, beim drücken des Buttons, ausgeführt werden. Tut aber leider etwas völlig anderes:

Beim starten des Programms hat das Label einen zufälligen Text (Kreuz, Pik, Herz oder Karo), obwohl die Funktion zufall() nicht aufgerufen wurde. Und das was zufällig beim Programmstart als Labeltext ausgewählt wurde bleibt dort stehen, egal wie oft ich den Button Zufall drücke.

Hier der Quelltext:

Code: Alles auswählen

import tkinter as tk, random

def zufall():
    farben = ["Karo", "Herz", "Pik", "Kreuz"]
    ergebnis = random.choice(farben)
    lb1["text"] = str(ergebnis)

main = tk.Tk()

lb1 = tk.Label(main, width = 20, height = 2)
lb1.pack()

b1 = tk.Button(main, text = "Zufall", command = zufall())
b1.pack()

main.mainloop()
OS = Linux
Python = 3.1.2

Kann mir bitte jemand erklären was ich falsch mache?

Gruß

Nils
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Du musst als `command` einen „Callback“ haben, d.h. eine Funktion die die eigentliche Funktion aufruft. Das erreichst du am einfachsten mit einem `lambda`.

Code: Alles auswählen

import tkinter as tk, random

def zufall():
    farben = ["Karo", "Herz", "Pik", "Kreuz"]
    ergebnis = random.choice(farben)
    lb1["text"] = str(ergebnis)

main = tk.Tk()

lb1 = tk.Label(main, width = 20, height = 2)
lb1.pack()

b1 = tk.Button(main, text = "Zufall", command = lambda: zufall())
b1.pack()

main.mainloop()
NilsV
User
Beiträge: 30
Registriert: Dienstag 17. August 2010, 12:35

Hallo nomnom,

vielen Dank für die Hilfestellung, so wie von Dir beschrieben funktioniert es.

Ich bin gerade noch über eine andere Lösung gestolpert:
Wenn ich die Klammern hinter zufall, beim aufrufen der Funktion, weg lasse, geht es auch:

Code: Alles auswählen

b1 = tk.Button(main, text = "Zufall", command = zufall)
Wobei meine Lösung mich wieder verwirrt, weil eine Funktion ohne die Klammern aufzurufen, in allen anderen mir bekannten Situationen, zu einem Fehler führt.

Gruß

Nils
BlackJack

@NilsV: Du rufst die Funktion ja auch nicht auf. Das soll ja Tkinter machen wenn Du auf den Knopf drückst.

Und genau das war ja Dein Fehler am Anfang: *Du* hast die Funktion aufgerufen und das Ergebnis davon wurde an `command` gebunden und nicht die Funktion *selbst*.
NilsV
User
Beiträge: 30
Registriert: Dienstag 17. August 2010, 12:35

Hallo BlackJack,

vielen Dank, ich glaube ich habe es verstanden.

Wenn ich eine Funktion aufrufe immer mit Klammern.

Wenn ich den Namen einer Funktion ohne Klammern aufrufe, wird mir normalerweise die Position der Funktion (Speicherblock?) ausgegeben.

Dadurch das tkinter die Funktion aufruft (command = zufall), bzw. ein Befehl zum ausführen davor steht, will tkinter nur wissen was es ausführen soll / wo es sich befindet.

Inhaltlich als Merkhilfe soweit richtig?

Gruß

Nils
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Als Merkhilfe reicht das. Vielleicht noch als kleine Ergänzung: Eine Funktion ist im Prinzip nichts anderes als ein Objekt, wie ein String oder ein Integer. Du kannst daher auch Funktionen an einen Namen binden und, zum Beispiel als Parameter, durch die gegend reichen. Es wenn du versuchst die Funktion aufzurufen (die runden Klammern), wird geprüft, ob dies möglich ist.

Code: Alles auswählen

>>> def spam():
...     print "spam"
... 
>>> a = spam
>>> b = 2
>>> a()
spam
>>> b()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
Noch zu dem Speicherblock: Wenn du die von dir beschriebene Ausgabe bekommst, dann führst du die Funktion nicht aus, sondern bekommst Informationen über das Objekt. In diesem Fall weiß Python nicht, wie es die Funktion ausgeben soll und schreibt daher die Adresse des Objekts hin (zumindest in CPython). Wenn du einen Integer ausgeben möchtest, dann wird das erkannt und die Zahl hingeschrieben. Das wirst du im Detail aber alles noch selber rausfinden, wenn du mit eigenen Klassen und Objekten arbeitest.

Sebastian
Das Leben ist wie ein Tennisball.
NilsV
User
Beiträge: 30
Registriert: Dienstag 17. August 2010, 12:35

Hallo EyDu,

Vielen Dank für die Erklärung.

Gruß

Nils
Antworten