Suppose I have the following Button
made with Tkinter in Python:
import Tkinter as Tk
win = Tk.Toplevel()
frame = Tk.Frame(master=win).grid(row=
Building on Matt Thompsons answer : a class can be made callable so it can be used instead of a function:
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()
button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))
I believe should fix this
Let's say I have the GUI:
import tkinter as tk
root = tk.Tk()
btn = tk.Button(root, text="Press")
btn.pack()
root.mainloop()
See that when btn
is pressed it calls its own function which is very similar to button_press_handle
in the following example:
def button_press_handle(callback=None):
if callback:
callback() # Where exactly the method assigned to btn['command'] is being callled
with:
button_press_handle(btn['command'])
You can simply think that command
option should be set as, the reference to the method we want to be called, similar to callback
in button_press_handle
.
Without arguments
So if I wanted to print
something when the button is pressed I would need to set:
btn['command'] = print # default to print is new line
Pay close attention to the lack of ()
with the print
method which is omitted in the meaning that: "This is the method's name which I want you to call when pressed but don't call it just this very instant." However, I didn't pass any arguments for the print
so it printed whatever it prints when called without arguments.
With Argument(s)
Now If I wanted to also pass arguments to the method I want to be called when the button is pressed I could make use of the anonymous functions, which can be created with lambda statement, in this case for print
built-in method, like the following:
btn['command'] = lambda arg1="Hello", arg2=" ", arg3="World!" : print(arg1 + arg2 + arg3)
Without Arguments
You can also achieve that using lambda
statement but it is considered bad practice and thus I won't include it here. The good practice is to define a separate method, multiple_methods
, that calls the methods wanted and then set it as the callback to the button press:
def multiple_methods():
print("Vicariously") # the first inner callback
print("I") # another inner callback
With Argument(s)
In order to pass argument(s) to method that calls other methods, again make use of lambda
statement, but first:
def multiple_methods(*args, **kwargs):
print(args[0]) # the first inner callback
print(kwargs['opt1']) # another inner callback
and then set:
btn['command'] = lambda arg="live", kw="as the" : a_new_method(arg, opt1=kw)
Also further note that callback
can't really return
because it's only called inside button_press_handle
with callback()
as opposed to return callback()
. It does return
but not anywhere outside that function. Thus you should rather modify object(s) that are accessible in the current scope.
Below example will call a method that changes btn
's text each time the button is pressed:
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()
Mirror
One simple way would be to configure button
with lambda
like the following syntax:
button['command'] = lambda arg1 = local_var1, arg2 = local_var2 : function(arg1, arg2)
Use a lambda to pass the entry data to the command function if you have more actions to carry out, like this (I've tried to make it generic, so just adapt):
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
This will pass the information in the event to the button function. There may be more Pythonesque ways of writing this, but it works for me.
The best thing to do is use lambda as follows:
button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))