Hoe kan u argumenten doorgeven aan een knopcommando in TKIER?

Stel dat ik de volgende Buttongemaakt 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 actionwordt 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 lambdasin 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 partialuit 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 btnwordt ingedrukt, het zijn eigenfunctie aanroept die erg lijkt op button_press_handlein 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 commandmoet worden ingesteld als, de verwijzing naar de methode die we willen aanroepen, vergelijkbaar met callbackin button_press_handle.


Een methode aanroepen(Terugbellen) wanneer de knop wordt ingedrukt

Zonderargumenten

Dus als ik iets wil printwanneer 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 printmethode 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 printdus 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 printingebouwd 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 callbackniet echt kan returnomdat het alleen binnen button_press_handlewordt aangeroepen met callback()in tegenstelling tot return callback(). Het returnmaar 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 btnverandert 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()

Spiegel


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 Buttonmet lambdazoals 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 = 3in te stellen.


Antwoord 16

U moet lambda:

. gebruiken

button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))

Other episodes