Stel dat ik de volgende Button
gemaakt met Tkinter in Python:
import Tkinter as Tk
win = Tk.Toplevel()
frame = Tk.Frame(master=win).grid(row=1, column=1)
button = Tk.Button(master=frame, text='press', command=action)
De methode action
wordt geroepen wanneer ik op de knop druk, maar wat als ik enkele argumenten wil doorgeven aan de methode action
?
Ik heb geprobeerd met de volgende code:
button = Tk.Button(master=frame, text='press', command=action(someNumber))
Hiermee roept u de methode onmiddellijk op en drukt op de knop niets.
1, Autoriteit 100%
I Persoonlijk liever gebruiken lambdas
in zo’n scenario, omdat IMO het duidelijker en eenvoudiger is en u ook niet dwingt om veel wrappermethoden te schrijven als u geen controle over de gebelde methoden hebt methode, maar dat is zeker een kwestie van smaak.
Dat is hoe je het met een lambda zou doen (let op, er is ook een implementatie van currying in de functionele module, zodat je dat ook kunt gebruiken):
button = Tk.Button(master=frame, text='press', command= lambda: action(someNumber))
2, Autoriteit 42%
Dit kan ook worden gedaan met behulp van partial
uit de standaardbibliotheek functools , zoals dit:
from functools import partial
#(...)
action_with_arg = partial(action, arg)
button = Tk.Button(master=frame, text='press', command=action_with_arg)
Antwoord 3, autoriteit 7%
Voorbeeld GUI:
Stel dat ik de GUI heb:
import tkinter as tk
root = tk.Tk()
btn = tk.Button(root, text="Press")
btn.pack()
root.mainloop()
Wat gebeurt er als er op een knop wordt gedrukt
Zie dat wanneer btn
wordt ingedrukt, het zijn eigenfunctie aanroept die erg lijkt op button_press_handle
in het volgende voorbeeld:
def button_press_handle(callback=None):
if callback:
callback() # Where exactly the method assigned to btn['command'] is being callled
met:
button_press_handle(btn['command'])
Je kunt gewoon denken dat de optie command
moet worden ingesteld als, de verwijzing naar de methode die we willen aanroepen, vergelijkbaar met callback
in button_press_handle
.
Een methode aanroepen(Terugbellen) wanneer de knop wordt ingedrukt
Zonderargumenten
Dus als ik iets wil print
wanneer op de knop wordt gedrukt, moet ik het volgende instellen:
btn['command'] = print # default to print is new line
Let goed op het gebrekvan ()
met de print
methode die is weggelaten in de zin dat: “Dit is de naam van de methode die ik wil dat je aanroept als je erop drukt maarnoem het niet op dit moment.”Ik heb echter geen argumenten doorgegeven voor de print
dus het drukte alles af wat het afdrukt als het wordt aangeroepen zonder argumenten.
MetArgument(en)
Als ik nu ook argumenten zou willen doorgeven aan de methode die ik wil aanroepenwanneer de knop wordt ingedrukt, zou ik gebruik kunnen maken van de anonieme functies, die kunnen worden aangemaakt met lambda-instructie, in dit geval voor print
ingebouwd methode, zoals de volgende:
btn['command'] = lambda arg1="Hello", arg2=" ", arg3="World!" : print(arg1 + arg2 + arg3)
Aanroepen van meerderemethoden wanneer de knop wordt ingedrukt
ZonderArgumenten
Je kunt dat ook bereiken met de lambda
-instructie, maar het wordt als een slechte gewoonte beschouwd en daarom zal ik het hier niet opnemen. De goede gewoonte is om een aparte methode te definiëren, multiple_methods
, die de gewenste methoden aanroept en deze vervolgens in te stellen als de callback naar de druk op de knop:
def multiple_methods():
print("Vicariously") # the first inner callback
print("I") # another inner callback
MetArgument(en)
Om argument(en) door te geven aan een methode die andere methoden aanroept, maak je opnieuw gebruik van de lambda
-instructie, maar eerst:
def multiple_methods(*args, **kwargs):
print(args[0]) # the first inner callback
print(kwargs['opt1']) # another inner callback
en stel vervolgens in:
btn['command'] = lambda arg="live", kw="as the" : a_new_method(arg, opt1=kw)
Object(en) retourneren van de callback
Houd er ook rekening mee dat callback
niet echt kan return
omdat het alleen binnen button_press_handle
wordt aangeroepen met callback()
in tegenstelling tot return callback()
. Het return
maar nietergens buiten die functie. U moet dus liever object(en) wijzigendie toegankelijk zijn in het huidige bereik.
Compleet voorbeeld met algemeenObjectwijziging(en)
Het onderstaande voorbeeld roept een methode aan die de tekst van btn
verandert elke keer dat de knop wordt ingedrukt:
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()
Antwoord 4, autoriteit 4%
Python’s vermogen om standaardwaarden te geven voor functieargumenten geeft ons een uitweg.
def fce(x=myX, y=myY):
myFunction(x,y)
button = Tk.Button(mainWin, text='press', command=fce)
Zie: http://infohost.nmt. edu/tcc/help/pubs/tkinter/web/extra-args.html
Voor meer knoppen kunt u een functie maken die een functie retourneert:
def fce(myX, myY):
def wrapper(x=myX, y=myY):
pass
pass
pass
return x+y
return wrapper
button1 = Tk.Button(mainWin, text='press 1', command=fce(1,2))
button2 = Tk.Button(mainWin, text='press 2', command=fce(3,4))
button3 = Tk.Button(mainWin, text='press 3', command=fce(9,8))
Antwoord 5, autoriteit 2%
Om het antwoord van Nae wat uitgebreider te maken, hier is een volledig voorbeeld dat de mogelijkheid bevat om een variabele door te geven aan de callback die verschillende waarden voor elke knop bevat:
import tkinter as tk
def callback(text):
print(text)
top = tk.Tk()
Texts=["text1", "text2", "text3"]
Buttons=[]
for i, z in enumerate(Texts):
Buttons.append(tk.Button(top, text=z, command= lambda ztemp=z : callback(ztemp)))
Buttons[i].pack(side=tk.LEFT, padx=5)
top.mainloop()
Door een tijdelijke variabele ztemp te definiëren, wordt de waarde van die variabele vastgelegd op het moment dat de knop wordt gedefinieerd.
Antwoord 6, autoriteit 2%
Voortbouwend op het antwoord van Matt Thompson: een klasse kan aanroepbaar worden gemaakt, zodat deze kan worden gebruikt in plaats van een functie:
import tkinter as tk
class Callback:
def __init__(self, func, *args, **kwargs):
self.func = func
self.args = args
self.kwargs = kwargs
def __call__(self):
self.func(*self.args, **self.kwargs)
def default_callback(t):
print("Button '{}' pressed.".format(t))
root = tk.Tk()
buttons = ["A", "B", "C"]
for i, b in enumerate(buttons):
tk.Button(root, text=b, command=Callback(default_callback, b)).grid(row=i, column=0)
tk.mainloop()
7
Een eenvoudige manier zou zijn om Button
met lambda
zoals de volgende syntaxis te configureren:
button['command'] = lambda arg1 = local_var1, arg2 = local_var2 : function(arg1, arg2)
8
button = Tk.Button(master=frame, text='press', command= lambda: action(someNumber))
Ik geloof dat zou dit moeten oplossen
Antwoord 9
Het beste is om lambda als volgt te gebruiken:
button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))
Antwoord 10
Ik ben extreem laat, maar hier is een heel eenvoudige manier om het voor elkaar te krijgen.
import tkinter as tk
def function1(param1, param2):
print(str(param1) + str(param2))
var1 = "Hello "
var2 = "World!"
def function2():
function1(var1, var2)
root = tk.Tk()
myButton = tk.Button(root, text="Button", command=function2)
root.mainloop()
U wikkelt u gewoon de functie in die u in een andere functie wilt gebruiken en bel de tweede functie op de knop Druk op.
11
Ik ben hiervoor ook dit probleem tegengekomen.
U kunt Lambda gewoon gebruiken:
button = Tk.Button(master=frame, text='press', command= lambda: action(someNumber))
12
Gebruik lambda
import tkinter as tk
root = tk.Tk()
def go(text):
print(text)
b = tk.Button(root, text="Click", command=lambda: go("hello"))
b.pack()
root.mainloop()
Uitgang:
hello
13
Gebruik een lambda om de invoergegevens naar de opdrachtfunctie door te geven als u meer acties hebt om uit te voeren, zoals deze (ik heb geprobeerd het generiek te maken, dus gewoon aanpassen):
event1 = Entry(master)
button1 = Button(master, text="OK", command=lambda: test_event(event1.get()))
def test_event(event_text):
if not event_text:
print("Nothing entered")
else:
print(str(event_text))
# do stuff
Hierdoor wordt de informatie in de gebeurtenis doorgegeven aan de knopfunctie. Er zijn misschien meer Python-achtige manieren om dit te schrijven, maar het werkt voor mij.
Antwoord 14
JasonPy – een paar dingen…
als je een knop in een lus plakt, wordt deze steeds opnieuw gemaakt… wat waarschijnlijk niet is wat je wilt. (misschien wel)…
De reden dat het altijd de laatste index krijgt, is dat lambda-gebeurtenissen worden uitgevoerd wanneer u erop klikt – niet wanneer het programma start. Ik weet niet 100% zeker wat je doet, maar probeer misschien de waarde op te slaan wanneer deze is gemaakt en roep hem later op met de lambda-knop.
bijvoorbeeld: (gebruik deze code niet, slechts een voorbeeld)
for entry in stuff_that_is_happening:
value_store[entry] = stuff_that_is_happening
dan kun je zeggen….
button... command: lambda: value_store[1]
hoop dat dit helpt!
Antwoord 15
Voor het nageslacht: je kunt klassen ook gebruiken om iets soortgelijks te bereiken. Bijvoorbeeld:
class Function_Wrapper():
def __init__(self, x, y, z):
self.x, self.y, self.z = x, y, z
def func(self):
return self.x + self.y + self.z # execute function
Knop kan dan eenvoudig worden gemaakt door:
instance1 = Function_Wrapper(x, y, z)
button1 = Button(master, text = "press", command = instance1.func)
Met deze benadering kunt u ook de functieargumenten wijzigen door bijvoorbeeld instance1.x = 3
in te stellen.
Antwoord 16
U moet lambda:
. gebruiken
button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))