How to pass an argument to event handler in tkinter?

48,963

Solution 1

You can use lambda to define an anonymous function, such as:

data={"one": 1, "two": 2}

widget.bind("<ButtonPress-1>", lambda event, arg=data: self.on_mouse_down(event, arg))

Note that the arg passed in becomes just a normal argument that you use just like all other arguments:

def on_mouse_down(self, event, arg):
    print(arg)

Solution 2

What about

import functools
def callback(self, event, param):
    pass
arg = 123
widget.bind("", functools.partial(callback, param=arg))

Solution 3

I think that in most cases you don't need any argument to a callback because the callback can be an instance method which can access the instance members:

from Tkinter import *

class MyObj:
    def __init__(self, arg):
        self.arg = arg

    def callback(self, event):
        print self.arg

obj = MyObj('I am Obj')
root = Tk()
btn=Button(root, text="Click")
btn.bind('<Button-1>', obj.callback)
btn.pack()
root.mainloop()

But I think the functools solution proposed by Philipp is also very nice

Solution 4

How to pass an argument to event handler in tkinter?

Here is the simplest and easiest-to-read solution of them all I think:

widget.bind('<Button-1>', callback2)

# change "None" to whatever you want the default value to be
def callback(self, event, custom_arg=None): 
    # do something
    
def callback2(self, event):
    # set custom_arg to whatever you want it to be when Button-1 is pressed
    callback(event, custom_arg=something_you_set) 

Solution 5

Here is an entry on this from the New Mexico Tech Tkinter 8.5 Reference (https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/extra-args.html) ‌‌‌‌‍‬‍‌‌‌‌‍‬‬‍‌‌‌‌‍‬‌‬‌‌‌‌‍‬‌‬‌‌‌‌‍‬‍‍‌‌‌‌‍‌‬‌‌‌‌‍‬‬‍‌‌‌‌‍‌‌‌‌‌‍‬‬‌‌‌‌‌‍‬‍‌‌‌‌‍‬‬‍‌‌‌‌‍‬‌‬‌‌‌‌‍‬‌‬‌‌‌‌‍‬‍‍‌‌‌‌‍‌‬‌‌‌‌‍‬‬‍‌‌‌‌‍‌‌‌‌‌‍‬‬‌

‌‌‌‌‍‬‍‌‌‌‌‍‬‬‍‌‌‌‌‍‬‌‬‌‌‌‌‍‬‌‬‌‌‌‌‍‬‍‍‌‌‌‌‍‌‬‌‌‌‌‍‬‬‍‌‌‌‌‍‌‌‌‌‌‍‬‬‌

This way allows you to add as many arguments as you need:

‌‌‌‌‍‬‍‌‌‌‌‍‬‬‍‌‌‌‌‍‬‌‬‌‌‌‌‍‬‌‬‌‌‌‌‍‬‍‍‌‌‌‌‍‌‬‌‌‌‌‍‬‬‍‌‌‌‌‍‌‌‌‌‌‍‬‬‌

54.7. The extra arguments trick

Sometimes you would like to pass other arguments to a handler besides the event.

Here is an example. Suppose your application has an array of ten checkbuttons whose >widgets are stored in a list self.cbList, indexed by the checkbutton number in >range(10).

Suppose further that you want to write one handler named .__cbHandler for >events in all ten of these checkbuttons. The handler can get the actual Checkbutton >widget that triggered it by referring to the .widget attribute of the Event object that >gets passed in, but how does it find out that checkbutton's index in self.cbList?

It would be nice to write our handler with an extra argument for the checkbutton number, >something like this:

def __cbHandler(self, event, cbNumber):

But event handlers are passed only one argument, the event. So we can't use the function >above because of a mismatch in the number of arguments.

Fortunately, Python's ability to provide default values for function arguments gives us >a way out. Have a look at this code:

def __createWidgets(self):
    …
    self.cbList = []    # Create the checkbutton list
    for i in range(10):
        cb = tk.Checkbutton(self, …)
        self.cbList.append(cb)
        cb.grid( row=1, column=i)
        def handler(event, self=self, i=i):   1
            return self.__cbHandler(event, i)
        cb.bind('<Button-1>', handler)
    …
def __cbHandler(self, event, cbNumber):
    …

These lines define a new function handler that expects three arguments. The first >argument is the Event object passed to all event handlers, and the second and third >arguments will be set to their default values—the extra arguments we need to pass it.

This technique can be extended to supply any number of additional arguments to >handlers.

Share:
48,963
sag
Author by

sag

Updated on August 09, 2021

Comments

  • sag
    sag almost 3 years
    widget.bind('<Button-1>',callback)   # binding 
    
    def callback(self,event)
        #do something
    

    I need to pass an argument to callback() . The argument is a dictionary object.

  • sag
    sag almost 14 years
    giving Exception: leftClickCallback() got an unexpected keyword argument 'param'
  • luc
    luc almost 14 years
    Does your callback as the param argument? This works ok form me.
  • sag
    sag almost 14 years
    self.l.bind("<Button-1>", functools.partial(self.leftClickCallback,param=fi)) this is the bind step.whats wrong here?
  • Philipp
    Philipp almost 14 years
    How is the leftClickCallback method declared?
  • sag
    sag almost 14 years
    def leftClickCallback(self,event,param):
  • sag
    sag almost 14 years
    then how to access that arg in the event handler? what should be the declaration of the handler
  • Russell Smith
    Russell Smith almost 14 years
    @sag: see my edit. Short answer: you access it like any other argument.
  • Ishrak
    Ishrak about 7 years
    Probably because, you did in two steps what you could have done in one. Just my opinion.
  • martineau
    martineau almost 3 years
    Regardless of whether the deletion of your comment was an unlucky incident or not, it added nothing to topic being discussed and @Ishrak's comment is likely true. Simply being the "simplest and easiest-to-read" do not a good answer make. For example, consider that adding two to a variable could be accomplished by doing v = v + 1 twice in a row or more succinct and efficiently in single statement via v += 2 — which is "better"?