Tkinter binding a function with arguments to a widget

I have a tkinter frame and a button attached to it:

from tkinter import *

def rand_func(a,b,c,effects):
    print (a+b+c)

root=Tk()
frame=Frame(root)
frame.bind("<Return>",lambda a=10, b=20, c=30: rand_func(a,b,c))
frame.pack()

button=Button(frame, text="click me", command=lambda a=1,b=2,c=3,eff=None:rand_func(a,b,c))
button.pack()

root.mainloop()

I want the same function to be done when user presses enter and when he presses the button. Sadly, the code above gives an error at the frame binding. Does anyone know a solution to this problem?

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

When you create a binding with bind, Tkinter automatically adds an argument that has information about the event. You’ll need to account for that either in your rand_func definition or in how you call it.

This argument is not included when you use the command attribute. You must take care to account for this extra argument either in how you call the function in each case, or in how the function interprets its parameters.

Here’s one solution that uses lambda in the binding to accept the extra event only when using bind command, but not pass it on to the final command.

import tkinter as tk

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.frame = tk.Frame(self)
        self.frame.pack()
        self.button = tk.Button(self.frame, text="click me",
                             command=lambda a=1, b=2, c=3: 
                                self.rand_func(a, b, c))
        self.button.pack()
        self.frame.bind("<Return>", 
                        lambda event, a=10, b=20, c=30: 
                            self.rand_func(a, b, c))
        # make sure the frame has focus so the binding will work
        self.frame.focus_set()

    def rand_func(self, a, b, c):
        print "self:", self, "a:", a, "b:", b, "c:", c
        print (a+b+c)

app = SampleApp()
app.mainloop()

That being said, it’s rare that binding to a frame is the right thing to do. Typically a frame won’t have keyboard focus, and unless it has focus the binding will never fire. If you are setting a global binding you should either bind to the “all” binding tag (using the bind_all method) or to the toplevel widget.

Solution 2

How about:

import tkinter as tk


def rand_func(eff=None, a=1, b=2, c=3):
    print(a + b + c)

root = tk.Tk()
root.bind("<Return>", lambda eff: rand_func(eff, a=10, b=20, c=30))

frame = tk.Frame(root)
frame.pack()

button = tk.Button(frame, text="click me",
                   command=lambda: rand_func(None, 1, 2, 3))
button.pack()

root.mainloop()

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply