Home > Software design >  tkinter: passing event arguments and additional arguments to an event handler function
tkinter: passing event arguments and additional arguments to an event handler function

Time:09-09

I would like to pass both event and an additional argument to a handler function. The purpose of this is to display a context menu using the x_root and y_root arguments of the event object.

I have tried the two techniques shown below. For simplicity, I prefer the one that uses the lambda function, but it doesn't work.

Is it possible to fix it? Any idea or explanation?

import tkinter as tk
    
class Example:

    def __init__(self, window):
        base = tk.Frame(window).pack()

        for i in range(3):
            l = tk.Label(base, text='label ' str(i))
            l.pack()

            def interhandler(event, self=self, i=i):
                return self._handler_one(event, i)

            l.bind("<Button-1>", interhandler)
            l.bind("<Button-3>", lambda event, i=i: self._handler_two(i))

    def _handler_one(self, event, k):
        print(event) # works
        print('left click on label', k)

    def _handler_two(self, k):
        print(event) # does not work
        print('right click on label ', k)

main = tk.Tk()
example = Example(main)
main.mainloop()

CodePudding user response:

If you want to send both values then function should get both values

def _handler_two(self, event, k):  # <--- event
    print(event)  # now it works
    print('right click on label ', k)

And you should send both values

lambda event, i=i: self._handler_two(event, i)  # <--- event

Full working code

import tkinter as tk
    
class Example:

    def __init__(self, window):
        base = tk.Frame(window).pack()

        for i in range(3):
            l = tk.Label(base, text='label ' str(i))
            l.pack()

            def interhandler(event, self=self, i=i):
                return self._handler_one(event, i)

            l.bind("<Button-1>", interhandler)
            l.bind("<Button-3>", lambda event, i=i: self._handler_two(event, i))  # <--- event

    def _handler_one(self, event, k):
        print(event) # works
        print('left click on label', k)

    def _handler_two(self, event, k):  # <--- event
        print(event)  # now it works
        print('right click on label ', k)

main = tk.Tk()
example = Example(main)
main.mainloop()

CodePudding user response:

Issues: You have not passed the event argument when you invoke your _handler_two callback function. Your callback function should also take two arguments, the event and the additional value.

Solution: Your code with the corrections can be found below:

import tkinter as tk


class Example:

    def __init__(self, window):
        base = tk.Frame(window).pack()

        for i in range(3):
            l = tk.Label(base, text='label '   str(i))
            l.pack()

            def interhandler(event, self=self, i=i):
                return self._handler_one(event, i)

            l.bind("<Button-1>", interhandler)
            l.bind("<Button-3>", lambda event, i=i: self._handler_two(event, i))

    def _handler_one(self, event, k):
        print(event)
        print('left click on label', k)

    def _handler_two(self, event, k):
        print(event)
        print('right click on label ', k)


main = tk.Tk()
example = Example(main)
main.mainloop()

Sample Output: Below is the resulting window:

enter image description here

Below is the output after clicking the right mouse button on label 0:

<ButtonPress event state=Mod1 num=3 x=29 y=16>
right click on label  0

Alternatively: You can define your function to take a variable number of arguments:

def _handler_two(self, *args):
    print(args[0])
    print('right click on label ', args[1])
  • Related