Comment passer des arguments à une commande bouton dans Tkinter?

supposons que j'ai le suivant Button fait avec Tkinter en 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)

la méthode action s'appelle quand j'appuie sur le bouton, mais que faire si je voulais passer quelques arguments à la méthode action ?

j'ai essayé avec le code suivant:

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

cela invoque juste la méthode immédiatement, et en appuyant sur le bouton ne fait rien.

96
demandé sur nbro 2011-08-03 04:18:14

11 réponses

personnellement, je préfère utiliser lambdas dans un tel scénario, parce que imo c'est plus clair et plus simple et aussi ne vous oblige pas à écrire beaucoup de méthodes d'enrubannage si vous n'avez pas le contrôle sur la méthode appelée, mais c'est certainement une question de goût.

C'est comme ça qu'on le ferait avec une lambda (notez qu'il y a aussi une implémentation de currying dans le module fonctionnel, donc vous pouvez l'utiliser aussi):

button = Tk.Button(master=frame, text='press', command= lambda: action(someNumber))
164
répondu Voo 2015-05-04 00:43:53

cela peut aussi être fait en utilisant partial de la bibliothèque standard functools , comme ceci:

from functools import partial
#(...)
action_with_arg = partial(action, arg)
button = Tk.Button(master=frame, text='press', command=action_with_arg)
45
répondu Dologan 2014-03-10 00:57:19
La capacité de

Python à fournir des valeurs par défaut pour les arguments de fonction nous donne une solution.

def fce(x=myX, y=myY):
    myFunction(x,y)
button = Tk.Button(mainWin, text='press', command=fce)

voir: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/extra-args.html

pour plus de boutons, vous pouvez créer une fonction qui renvoie une fonction:

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))
7
répondu MarrekNožka 2014-12-03 21:54:27

exemple GUI:

disons que j'ai L'interface graphique:

import tkinter as tk

root = tk.Tk()

btn = tk.Button(root, text="Press")
btn.pack()

root.mainloop()

Ce qui se Passe Quand un Bouton Est Pressé

voir que lorsque btn est pressé il appelle sa propre fonction qui est très similaire à button_press_handle dans l'exemple suivant:

def button_press_handle(callback=None):
    if callback:
        callback() # Where exactly the method assigned to btn['command'] is being callled

avec:

button_press_handle(btn['command'])

vous pouvez simplement penser que command option devrait être, la référence à la méthode que nous voulons être appelé, similaire à callback dans button_press_handle .


l'Appel d'une Méthode( Rappel ) Quand le Bouton est Pressé

sans arguments

donc si je voulais print quelque chose quand le bouton est appuyé je devrais mettre:

btn['command'] = print # default to print is new line

prêtez une attention particulière au manque de () avec la méthode print qui est omis dans le sens que: " C'est le nom de la méthode que je veux que vous appeliez quand vous appuyez sur mais ne l'appelez pas juste ce moment." cependant, je n'ai pas passé d'arguments pour le print de sorte qu'il imprimé tout ce qu'il imprime lorsqu'il est appelé sans arguments.

avec Argument (S)

maintenant si je voulais aussi passer des arguments à la méthode que je veux être appelé quand le bouton est appuyé je pourrais faire usage des fonctions anonymes, qui peuvent être créées avec lambda déclaration, dans ce cas pour print méthode intégrée, comme la suivante:

btn['command'] = lambda arg1="Hello", arg2=" ", arg3="World!" : print(arg1 + arg2 + arg3)

appel Multiple méthodes lorsque le bouton est pressé

Sans Arguments

vous pouvez également obtenir que l'utilisation de lambda déclaration, mais il est considéré comme une mauvaise pratique et donc je ne vais pas l'inclure ici. La bonne pratique consiste à définir une méthode séparée, multiple_methods , qui appelle les méthodes désirées et ensuite la définir comme le rappel à la pression de bouton:

def multiple_methods():
    print("Vicariously") # the first inner callback
    print("I") # another inner callback

avec Argument(S)

afin de passer d'argument(s) à la méthode qui appelle d'autres méthodes, l'utilisation de lambda déclaration, mais d'abord:

def multiple_methods(*args, **kwargs):
    print(args[0]) # the first inner callback
    print(kwargs['opt1']) # another inner callback

et ensuite:

btn['command'] = lambda arg="live", kw="as the" : a_new_method(arg, opt1=kw)

le Retour de l'Objet(s) à Partir de la fonction de Rappel

aussi noter que callback ne peut pas vraiment return parce qu'il est seulement appelé à l'intérieur button_press_handle avec callback() par opposition à return callback() . Il fait return mais pas n'importe où en dehors de cette fonction. Ainsi, vous devriez plutôt modifier objet (s) qui sont accessibles dans la portée actuelle.


Exemple Complet avec global Objet de la Modification(s)

exemple ci-Dessous appelez une méthode qui change le texte de btn chaque fois que le bouton est appuyé:

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()

miroir

3
répondu Nae 2018-01-21 16:12:12

la raison pour laquelle il invoque la méthode immédiatement et en appuyant sur le bouton ne fait rien est que action(somenumber) est évalué et sa valeur de retour est attribuée comme la commande pour le bouton. Donc si action imprime quelque chose pour vous dire qu'il a couru et retourne None , vous n'avez qu'à lancer action pour évaluer sa valeur de retour et donner None comme commande pour le bouton.

avoir des boutons pour appeler des fonctions avec des arguments différents que vous pouvez utiliser les variables globales, bien que je ne peux pas le recommander:

import Tkinter as Tk

frame = Tk.Frame(width=5, height=2, bd=1, relief=Tk.SUNKEN)
frame.grid(row=2,column=2)
frame.pack(fill=Tk.X, padx=5, pady=5)
def action():
    global output
    global variable
    output.insert(Tk.END,variable.get())
button = Tk.Button(master=frame, text='press', command=action)
button.pack()
variable = Tk.Entry(master=frame)
variable.pack()
output = Tk.Text(master=frame)
output.pack()

if __name__ == '__main__':
    Tk.mainloop()

ce que je ferais, c'est faire un class dont les objets contiendraient toutes les variables requises et les méthodes pour les changer au besoin:

import Tkinter as Tk
class Window:
    def __init__(self):
        self.frame = Tk.Frame(width=5, height=2, bd=1, relief=Tk.SUNKEN)
        self.frame.grid(row=2,column=2)
        self.frame.pack(fill=Tk.X, padx=5, pady=5)

        self.button = Tk.Button(master=self.frame, text='press', command=self.action)
        self.button.pack()

        self.variable = Tk.Entry(master=self.frame)
        self.variable.pack()

        self.output = Tk.Text(master=self.frame)
        self.output.pack()

    def action(self):
        self.output.insert(Tk.END,self.variable.get())

if __name__ == '__main__':
    window = Window()
    Tk.mainloop()
1
répondu berna1111 2016-10-17 19:59:48

une façon simple serait de configurer button avec lambda comme la syntaxe suivante:

button['command'] = lambda arg1 = local_var1, arg2 = local_var2 : function(arg1, arg2)
1
répondu Nae 2017-12-10 21:48:05
button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))

je crois devrait corriger cet

1
répondu Harrison Sills 2018-04-04 20:31:27

utilisez un lambda pour passer les données d'entrée à la fonction de commande si vous avez plus d'actions à effectuer, comme ceci (j'ai essayé de le rendre générique, donc il suffit de s'adapter):

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

ceci transmettra les informations dans l'événement à la fonction bouton. Il y a peut-être d'autres façons Pythonesques d'écrire ça, mais ça marche pour moi.

0
répondu Jayce 2017-06-22 17:33:25

JasonPy-quelques petites choses...

si vous insérez un bouton dans une boucle, il sera créé encore et encore et encore... ce qui n'est probablement pas ce que vous voulez. (peut-être que c'est)...

la raison pour laquelle il obtient toujours le dernier index est lambda events run quand vous les Cliquez - pas quand le programme commence. Je ne suis pas sûr à 100% de ce que vous faites mais peut-être essayer de stocker la valeur quand il est fait puis l'appeler plus tard avec le bouton lambda.

eg: (n'utilisez pas ce code, juste un exemple)

for entry in stuff_that_is_happening:
    value_store[entry] = stuff_that_is_happening

, alors vous pouvez dire....

button... command: lambda: value_store[1]

espérons que cette aide!

0
répondu David W. Beck 2017-11-10 10:09:16

Pour la postérité: vous pouvez également utiliser des classes pour obtenir quelque chose de similaire. Par exemple:

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
Le bouton

peut alors être créé simplement par:

instance1 = Function_Wrapper(x, y, z)
button1  = Button(master, text = "press", command = instance1.func)

cette approche vous permet également de modifier les arguments de fonction en mettant instance1.x = 3 .

0
répondu Matt Thompson 2018-02-14 03:28:51

construire sur Matt Thompson réponse : une classe peut être rendue callable afin qu'il puisse être utilisé à la place d'une fonction:

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()
0
répondu Christoph Frings 2018-06-08 13:53:41