Mein Code lautet:
from Tkinter import *
admin = Tk()
def button(an):
print an
print 'het'
b = Button(admin, text='as', command=button('hey'))
b.pack()
mainloop()
Die Taste funktioniert nicht, sie gibt einmal ohne meinen Befehl 'hey' und 'het' aus, und wenn ich die Taste drücke, passiert nichts.
Antworten:
Betrachten Sie diesen Code:
b = Button(admin, text='as', command=button('hey'))
Es macht genau das Gleiche wie folgt:
result = button('hey') b = button(admin, text='as', command=result)
Die
command
Option verweist auf eine Funktion. Dies ist eine ausgefallene Art zu sagen, dass Sie ihr den Namen der Funktion übergeben müssen. Um eine Referenz zu übergeben, dürfen Sie nur den Namen verwenden, ohne Klammern oder Argumente zu verwenden. Zum Beispiel:Wenn Sie einen Parameter wie "hey" übergeben möchten, müssen Sie einen kleinen zusätzlichen Code verwenden:
button
Funktion aufruft .lambda
eine so genannte anonyme Funktion erstellen . In jeder Hinsicht ist es eine Funktion, außer dass sie keinen Namen hat. Wenn Sie denlambda
Befehl aufrufen, wird ein Verweis auf die erstellte Funktion zurückgegeben. Dies bedeutet, dass er für den Wert dercommand
Option für die Schaltfläche verwendet werden kann.Für mich
lambda
ist es das einfachste, da es keine zusätzlichen Importefunctools.partial
erfordert, obwohl einige Leute denken, dassfunctools.partial
das leichter zu verstehen ist.Um eine Lambda-Funktion zu erstellen, die Ihre
button
Funktion mit einem Argument aufruft, gehen Sie folgendermaßen vor :lambda: button('hey')
Sie erhalten eine Funktion, die funktional äquivalent ist zu:
def some_name(): button('hey')
Gibt, wie bereits erwähnt,
lambda
einen Verweis auf diese namenlose Funktion zurück. Da die Referenz eine Referenzcommand
erwartet, können Sie dieselambda
direkt beim Erstellen der Schaltfläche verwenden:b = Button(... command = lambda: button('hey'))
Es gibt eine Frage auf dieser Seite, die viele interessante Kommentare zu Lambda im Allgemeinen enthält. Siehe die Frage Warum Python Lambdas nützlich sind? . Dieselbe Diskussion enthält eine Antwort, die zeigt, wie Lambdas in einer Schleife verwendet werden, wenn Sie eine Variable an den Rückruf übergeben müssen.
Schließlich finden Sie im Abschnitt mit dem Titel Tkinter Callbacks auf effbot.org ein nettes Tutorial. Die Abdeckung von Lambda ist ziemlich mager, aber die Informationen dort könnten immer noch nützlich sein.
quelle
Sie müssen eine Funktion ohne Parameter erstellen, die Sie als Befehl verwenden können:
b = Button(admin, text='as', command=lambda: button('hey'))
Weitere Informationen finden Sie im Abschnitt "Übergeben von Argumenten an Rückrufe" in diesem Dokument .
quelle
Beispiel GUI:
Angenommen, ich habe die GUI:
import tkinter as tk root = tk.Tk() btn = tk.Button(root, text="Press") btn.pack() root.mainloop()
Was passiert, wenn eine Taste gedrückt wird?
Beachten Sie, dass beim
btn
Drücken eine eigene Funktion aufgerufen wird, die derbutton_press_handle
im folgenden Beispiel sehr ähnlich ist :def button_press_handle(callback=None): if callback: callback() # Where exactly the method assigned to btn['command'] is being callled
mit:
button_press_handle(btn['command'])
Sie können sich einfach vorstellen, dass diese
command
Option als Verweis auf die Methode festgelegt werden sollte, die aufgerufen werden soll, ähnlich wiecallback
inbutton_press_handle
.Aufrufen einer Methode ( Rückruf ) Wenn die Taste gedrückt wird
Ohne Argumente
Wenn ich also
print
etwas wollte, wenn die Taste gedrückt wird, müsste ich Folgendes einstellen:btn['command'] = print # default to print is new line
Achten Sie auf das Fehlen von
()
mit demprint
Verfahren , das im Sinne weggelassen wird , dass: „Das ist der Name der Methode, die ich Sie wollen , wenn sie gedrückt nennen , aber . Sie es nicht nur diesem Augenblick nennen“ Ich habe jedoch keine Argumente für das übergeben,print
sodass gedruckt wurde, was auch immer gedruckt wird, wenn es ohne Argumente aufgerufen wird.Mit Argument (en)
Wenn ich nun auch Argumente an die Methode übergeben möchte, die beim Drücken der Schaltfläche aufgerufen werden soll, kann ich die anonymen Funktionen verwenden, die mit der Lambda- Anweisung erstellt werden können, in diesem Fall für die
print
integrierte Methode wie die folgende ::btn['command'] = lambda arg1="Hello", arg2=" ", arg3="World!" : print(arg1 + arg2 + arg3)
Aufrufen mehrerer Methoden, wenn die Taste gedrückt wird
Ohne Argumente
Sie können dies auch mit der
lambda
Anweisung erreichen, aber es wird als schlechte Praxis angesehen und daher werde ich es hier nicht aufnehmen. Es empfiehlt sich, eine separate Methode zu definierenmultiple_methods
, die die gewünschten Methoden aufruft und diese dann als Rückruf für den Tastendruck festlegt:def multiple_methods(): print("Vicariously") # the first inner callback print("I") # another inner callback
Mit Argument (en)
Um Argumente an Methoden zu übergeben, die andere Methoden aufrufen, verwenden Sie erneut die
lambda
Anweisung, aber zuerst:def multiple_methods(*args, **kwargs): print(args[0]) # the first inner callback print(kwargs['opt1']) # another inner callback
und dann setzen:
btn['command'] = lambda arg="live", kw="as the" : a_new_method(arg, opt1=kw)
Rückgabe von Objekten aus dem Rückruf
Beachten Sie auch, dass
callback
dies nicht wirklich möglich ist,return
da es nur von innenbutton_press_handle
mitcallback()
im Gegensatz zu aufgerufen wirdreturn callback()
. Es tutreturn
aber nicht überall außerhalb dieser Funktion. Daher sollten Sie lieber Objekte ändern , auf die im aktuellen Bereich zugegriffen werden kann.Vollständiges Beispiel mit globalen Objektmodifikationen.
Das folgende Beispiel ruft eine Methode auf, die
btn
den Text jedes Mal ändert , wenn die Taste gedrückt wird:import tkinter as tk i = 0 def text_mod(): global i, btn # btn can be omitted but not sure if should be txt = ("Vicariously", "I", "live", "as", "the", "whole", "world", "dies") btn['text'] = txt[i] # the global object that is modified i = (i + 1) % len(txt) # another global object that gets modified root = tk.Tk() btn = tk.Button(root, text="My Button") btn['command'] = text_mod btn.pack(fill='both', expand=True) root.mainloop()
Spiegel
quelle
Die Engine wertet das Ergebnis der Funktion aus, wenn sie den Wert in der Zeile "... command = ..." zuweist.
Der "Befehl" erwartet die Rückgabe einer Funktion. Aus diesem Grund kann die Verwendung eines Lambda die Aufgabe erfüllen, da eine anomymische Funktion erstellt wird, die während der Auswertung an den "Befehl" zurückgegeben wird. Sie können auch Ihre eigene Funktion codieren, sie erledigt auch die Arbeit.
Dies ist ein Beispiel mit Lambda und ohne Lambda:
#!/usr/bin/python # coding=utf-8 from Tkinter import * # Creation de la fenêtre principale (main window) Mafenetre = Tk() res1 = StringVar() res2 = StringVar() def isValidInput(obj): if hasattr(obj, 'get') and callable(getattr(obj, 'get')): return TRUE return FALSE # stupid action 2 (return 12 on purpose to show potential mistake) def action1(*arguments): print "action1 running" for arg in arguments: if isValidInput(arg): print "input value: ", arg.get() res1.set(arg.get()) else: print "other value:", arg print "\n" return 12 # stupid action 2 def action2(*arguments): print "action2 running" a = arguments[0] b = arguments[1] if isValidInput(a) and isValidInput(b): c = a.get() + b.get() res2.set(c) print c print "\n" # a stupid workflow manager ordered by name def start_tasks(*arguments, **keywords): keys = sorted(keywords.keys()) for kw in keys: print kw, "plugged " keywords[kw](*arguments) # valid callback wrapper with lambda def action1_callback(my_input): return lambda args=[my_input]: action1(*args) # valid callback wrapper without lambda def action1_callback_nolambda(*args, **kw): def anon(): action1(*args) return anon # first input string input1 = StringVar() input1.set("delete me...") f1 = Entry(Mafenetre, textvariable=input1, bg='bisque', fg='maroon') f1.focus_set() f1.pack(fill="both", expand="yes", padx="5", pady=5) # failed callback because the action1 function is evaluated, it will return 12. # in this case the button won't work at all, because the assignement expect a function # in order to have the button command to execute something ba1 = Button(Mafenetre) ba1['text'] = "show input 1 (ko)" ba1['command'] = action1(input1) ba1.pack(fill="both", expand="yes", padx="5", pady=5) # working button using a wrapper ba3 = Button(Mafenetre) ba3['text'] = "show input 1 (ok)" # without a lambda it is also working if the assignment is a function #ba1['command'] = action1_callback_nolambda(input1) ba3['command'] = action1_callback(input1) ba3.pack(fill="both", expand="yes", padx="5", pady=5) # display result label Label1 = Label(Mafenetre, text="Action 1 result:") Label1.pack(fill="both", expand="yes", padx="5", pady=5) # display result value resl1 = Label(Mafenetre, textvariable=res1) resl1.pack(fill="both", expand="yes", padx="5", pady=5) # second input string input2 = StringVar() f2 = Entry(Mafenetre, textvariable=input2, bg='bisque', fg='maroon') f2.focus_set() f2.pack(fill="both", expand="yes", padx="5", pady=5) # third test without wrapper, but making sure that several arguments are well handled by a lambda function ba2 = Button(Mafenetre) ba2['text'] = "execute action 2" ba2['command'] = lambda args=[input1, input2], action=action2: start_tasks(*args, do=action) ba2.pack(fill="both", expand="yes", padx="5", pady=5) # display result label Label2 = Label(Mafenetre, text="Action 2 result:") Label2.pack(fill="both", expand="yes", padx="5", pady=5) # display result value resl2 = Label(Mafenetre, textvariable=res2) resl2.pack(fill="both", expand="yes", padx="5", pady=5) Mafenetre.mainloop()
quelle
Ich denke, der beste Weg, um dieses Problem zu lösen, ist die Verwendung einer Lambda-Funktion.
from tkinter import * admin= Tk() def button(an): print(an) print("het") b = Button(admin, text="as", command=lambda: button("hey")) b.pack() mainloop()
Wenn Sie das Befehlsschlüsselwort nicht verwenden möchten, können Sie stattdessen die Methode .bind () verwenden:
from tkinter import * admin= Tk() def button(an): print(an) print("het") b = Button(admin, text="as") b.pack() b.bind("<Button-1>", lambda bb: button("hey")) mainloop()
Die Verwendung einer Mutterfunktion (kein Parameter), die die untergeordnete Funktion (mindestens 1 Parameter) besitzt, die Sie aufrufen möchten, ist dumm.
Nur um mit Ihnen zu teilen, dies ist eines meiner Programme:
import tkinter window = tkinter.Tk() def plus_them(field_1, field_2, field_3): field_3.delete(0, 'end') num1 = 0 num2 = 0 try: num1 = int(field_1.get()) num2 = int(field_2.get()) except: print("Exception occurs") else: print("Continue") result = num1 + num2 field_3.insert(tkinter.END, str(result)) return result def minus_them(field_1, field_2, field_3): field_3.delete(0, 'end') num1 = 0 num2 = 0 try: num1 = int(field_1.get()) num2 = int(field_2.get()) except: print("Exception occurs") else: print("Continue") result = num1 - num2 field_3.insert(tkinter.END, str(result)) return result #Input Panel: label_1 = tkinter.Label(window, text="First Number:") label_1.grid(row=0, column=0) label_2 = tkinter.Label(window, text="Second Number:") label_2.grid(row=1, column=0) entry_1 = tkinter.Entry(window) entry_1.grid(row=0, column=1) entry_2 = tkinter.Entry(window) entry_2.grid(row=1, column=1) #Button Panel: button_1 = tkinter.Button(window, text="Plus") button_1.grid(row=2, column=0) button_2 = tkinter.Button(window, text="Minus") button_2.grid(row=2, column=1) #Answer Panel: label_3 = tkinter.Label(window, text="The Answer:") label_3.grid(row=3, column=0) entry_3 = tkinter.Entry(window) entry_3.grid(row=3, column=1) #Event Handling: button_1.bind("<Button-1>", lambda p: plus_them(entry_1, entry_2, entry_3)) button_2.bind("<Button-1>", lambda m: minus_them(entry_1, entry_2, entry_3)) #Window Stuff: window.title("Plus and Minus Calculator") window.mainloop()
Das ist es.
quelle