The notion of "returning" values from callbacks doesn't make sense in the context of an event driven program. Callbacks are called as the result of an event, so there's nowhere to return a value to.
As a general rule of thumb, your callbacks should always call a function, rather than using functools.partial or lambda. Those two are fine when needed, but if you're using an object-oriented style of coding they are often unnecessary, and lead to code that is more difficult to maintain than it needs to be.
For example:
def compute():
value = var.get()
result = square(value)
list_of_results.append(result)
button = Tk.Button(root, text='click', command = compute)
...
This becomes much easier, and you can avoid global variables, if you create your application as a class:
class App(...):
...
def compute():
...
result = self.square(self.var.get())
self.results.append(result)
Answer from Bryan Oakley on Stack OverflowThe notion of "returning" values from callbacks doesn't make sense in the context of an event driven program. Callbacks are called as the result of an event, so there's nowhere to return a value to.
As a general rule of thumb, your callbacks should always call a function, rather than using functools.partial or lambda. Those two are fine when needed, but if you're using an object-oriented style of coding they are often unnecessary, and lead to code that is more difficult to maintain than it needs to be.
For example:
def compute():
value = var.get()
result = square(value)
list_of_results.append(result)
button = Tk.Button(root, text='click', command = compute)
...
This becomes much easier, and you can avoid global variables, if you create your application as a class:
class App(...):
...
def compute():
...
result = self.square(self.var.get())
self.results.append(result)
Sorry for being 6 years late, but recently I figured out a good way to do this without making your code messy and hard to maintain. This is pretty much what DaveTheScientist has said, but I just want to expand on it a little. Usually, in Tkinter, if you want to have a button call a function, you do the following:
exampleButton = Button(root, text = 'Example', command = someFunc)
This will simply call someFunc whenever the button is pressed. If this function, however, takes arguments, you need to use lambdas and do something like this:
exampleButton = Button(root, text = 'Example', command = lambda: someFunc(arg1, arg2))
The above line of code will run someFunc and use the variables arg1 and arg2 as arguments for that function. Now, what you could do in a program where, a lot of the times, you would need the functions run by buttons to return values, is create a new function which is called by every button.
This function takes the function you want your button to run as a first argument, and that function's arguments afterwards.
def buttonpress(function, *args):
value = function(*args)
Then when you create the button, you do:
exampleButton = Button(root, text = 'Example', command = lambda: buttonpress( someFunc, arg1, arg2 ))
This will run the given function (in this case, someFunc) and store the returned value in the value variable. It also has the advantage that you can use as many arguments as you want for the function your button runs.
Videos
Easy fix is to initialize the lambda function with the current value of i each time the lambda function is created. This can be done using Python default values for another dummy variable j.
command = lambda j=i: myfunction(j)
Blender's answer is a clever solution but in case you get thrown off by the function abstraction, here is another possible way to do it. It really just creates a mapping, saved in buttons, from Button widgets to their proper numbers.
import Tkinter as tk
root = tk.Tk()
def myfunction(event):
print buttons[event.widget]
buttons = {}
for i in range(10):
b = tk.Button(root, text='button' + str(i))
buttons[b] = i # save button, index as key-value pair
b.bind("<Button-1>", myfunction)
b.place(x=10,y=(10+(25*i)))
root.mainloop()
This should work:
...
btnaText='ButtonA'
btna = Button(root, text = btnaText, command = lambda: sayHi(btnaText))
btna.pack()
For more information take a look at Tkinter Callbacks
text is not a function in your case. Just have it as:
value = 'ButtonA'
btna = Button(root, text = value, command = lambda: sayHi(value))
And you will get that working.
SearchIP() is not part of tk or root so use command=SearchIP
And use def SearchIP(): - you don't have to pass root as argument.
--
If you need to pass argument to SearchIP(some-argument) then you have to use command=lambda:SearchIP(passed-argument)
SearchIP() is called before it is defined. The error message is simply saying that the interpreter doesn't know what SearchIP is at the time the call to that function is made higher up in the script. To fix that move the definition of SearchIP up above the call or move the call down below the definition, or both.
I cannot imagine any case and Im not sure at all if this answers your question but it maybe equivalent for what you are looking for:
The invoke method of the button seems pretty equivalent to me. So solution-1 would be:
import tkinter as tk
def hi():
print('hello')
root = tk.Tk()
b = tk.Button(root, text='test', command=hi)
b.pack()
cmd = b.invoke
#cmd = lambda :b._do('invoke')
root.mainloop()
If this isnt what you looking for you could call the function in tcl level. Solution-2:
import tkinter as tk
def hi():
print('hello')
root = tk.Tk()
b = tk.Button(root, text='test', command=hi)
b.pack()
cmd = lambda :root.tk.call(b['command'])
#cmd= lambda :root.tk.eval(b['command'])
cmd()
root.mainloop()
Solution 3, would be to return your function by invoke:
import tkinter as tk
def hi():
print('hello')
return hi
root = tk.Tk()
b = tk.Button(root, text='test', command=hi)
b.pack()
cmd = b.invoke()
print(cmd) #still a string but comparable
root.mainloop()
This is a more complex solution. It patches Misc._register, Misc.deletecommand and Misc.destroy to delete values from dict tkinterfuncs. In this example there are many print to check that values are added and removed from the dict.
import tkinter as tk
tk.tkinterfuncs = {} # name: func
def registertkinterfunc(name, func):
"""Register name in tkinterfuncs."""
# print('registered', name, func)
tk.tkinterfuncs[name] = func
return name
def deletetkinterfunc(name):
"""Delete a registered func from tkinterfuncs."""
# some funcs ('tkerror', 'exit') are registered outside Misc._register
if name in tk.tkinterfuncs:
del tk.tkinterfuncs[name]
# print('delete', name, 'tkinterfuncs len:', len(tkinterfuncs))
def _register(self, func, subst=None, needcleanup=1):
"""Return a newly created Tcl function. If this
function is called, the Python function FUNC will
be executed. An optional function SUBST can
be given which will be executed before FUNC."""
name = original_register(self, func, subst, needcleanup)
return registertkinterfunc(name, func)
def deletecommand(self, name):
"""Internal function.
Delete the Tcl command provided in NAME."""
original_deletecommand(self, name)
deletetkinterfunc(name)
def destroy(self):
"""
Delete all Tcl commands created for
this widget in the Tcl interpreter.
"""
if self._tclCommands is not None:
for name in self._tclCommands:
# print('- Tkinter: deleted command', name)
self.tk.deletecommand(name)
deletetkinterfunc(name)
self._tclCommands = None
def getcommand(self, name):
"""
Gets the command from the name.
"""
return tk.tkinterfuncs[name]
original_register = tk.Misc.register
tk.Misc._register = tk.Misc.register = _register
original_deletecommand = tk.Misc.deletecommand
tk.Misc.deletecommand = deletecommand
tk.Misc.destroy = destroy
tk.Misc.getcommand = getcommand
if __name__ == '__main__':
def f():
root.after(500, f)
root = tk.Tk()
root.after(500, f)
but1 = tk.Button(root, text='button1', command=f)
but1.pack()
but2 = tk.Button(root, text='button2', command=f)
but2.pack()
but3 = tk.Button(root, text='button3', command=lambda: print(3))
but3.pack()
print(root.getcommand(but1['command']))
print(root.getcommand(but2['command']))
print(root.getcommand(but3['command']))
but3['command'] = f
print(root.getcommand(but3['command']))
root.mainloop()