Short answer: you cannot. Callbacks can't return anything because there's nowhere to return it to -- except the event loop, which doesn't do anything with return values.
In an event based application, what you typically will do is set an attribute on a class. Or, if you're a beginner, you can set a global variable. Using a global variable isn't a good idea for real code that has to be maintained over time but it's OK for experimentation.
So, for example, since C appears to be a global variable in your example, you would do something like:
def button():
global C
mylabel = Label(myGui, text = "hi").grid(row = 0, column = 0)
A = B.get()
C = A
Answer from Bryan Oakley on Stack OverflowShort answer: you cannot. Callbacks can't return anything because there's nowhere to return it to -- except the event loop, which doesn't do anything with return values.
In an event based application, what you typically will do is set an attribute on a class. Or, if you're a beginner, you can set a global variable. Using a global variable isn't a good idea for real code that has to be maintained over time but it's OK for experimentation.
So, for example, since C appears to be a global variable in your example, you would do something like:
def button():
global C
mylabel = Label(myGui, text = "hi").grid(row = 0, column = 0)
A = B.get()
C = A
You could call C.set from within the button function:
def button:
mylabel = Label(myGui, text = "hi").grid(row = 0, column = 0)
A = B.get()
C.set(A)
# return A # return values are useless here
python - Returning values in lambda function while using Tkinter button - Stack Overflow
Understanding Python Lambda behavior with Tkinter Button - Stack Overflow
lambda tkinter not. able to return value from button callback - Stack Overflow
python 3.x - How to return value from tkinter button callback - Stack Overflow
Videos
Alright, so I am creating a small GUI program using tkinter, and one of the functions it performs requires a user to enter a document number. It then makes changes to the database based on the number entered, so I want to make sure the user entered it correctly.
To accomplish this, I am asking the user to enter the number again in a pop up window and then I compare the values and return True if they match or False otherwise.
I am having a hard time getting my def: to return the result of the lambda function inside of it.
I've tried assigning the lambda expression to a variable, but that seems to not return True or False as expected, but rather some internal Python stuff (memory addresses and such).
Am I trying to do this the right way? Is there a simpler way?
My code
When you use () with a function name(func(args)), then it is immediately calling/invoking the function while python is executing the line, you do not want that. You want to ONLY call the function when the button is clicked. tkinter will internally call the function for you, all you have to do is give the function name.
Why use lambda? Think of it as a function that returns another function, your code can be lengthened to:
func = lambda: comando_click("Nova_Mensagem")
botao = Button(menu_inicial, text = "Executar", command=func)
func is the function name and if you want to call it, you would say func(). And when you say command=comando_click("Nova_Mensagem") then command has the value returned by command click(because you call the function with ()), which is None and if I'm not wrong, if the given value is None, it will not be called by tkinter. Hence your function is executed just once because of () and as a result of calling the function, you are assigning the value of the function call(None) before the event loop starts processing the events.
Some other methods:
- Using
partialfromfunctools:
from functools import partial
botao = Button(.....,command=partial(comando_click,"Nova_Mensagem"))
- Using a helper function:
def helper(args):
def comando_click():
print(args)
return comando_click
botao = Button(...., command=helper("Nova_Mensagem"))
IMO, lambdas are the easiest way to proceed with calling a function with arguments.
In this code:
command=comando_click("Nova_Mensagem")
you have called the comando_click function, once, and assigned the result (None) to the command argument. Nothing will happen when command is called (in fact you should get a TypeError exception because None is not callable).
In this code:
command=lambda:comando_click("Nova_Mensagem")
you have not actually called comando_click yet -- you have created a new function (using lambda) that will in turn call comando_click when it is called. Every time the button is clicked, your new function will get called.
If the lambda is confusing, you can do the exact same thing with a def like this:
def button_command():
comando_click("Nova_Mensagem")
...
command=button_command # no ()! we don't want to actually call it yet!
The lambda expression is just an alternative to using def when you want to create a small single-use function that doesn't need a name (e.g. you want to make a function that calls another function with a specific argument, exactly as you're doing here).
You can't really do that. The best way to do it is with a function but I'm not sure why you would want to do that. It seems a bit odd... As commented, the a Tkinter script runs differently to a normal Python script so nothing will be able to use the returned value. Store it as a variable if you need it.
I would just create a function that stores it as a variable.
def foo():
gah=entry.get()
# return entry.get()
# stuff or no stuff
button=Button(root, text="ghost", command=foo)
Long story short: How do I pass a variable by reference?
Example of a mutable object that persists after the callback
import tkinter as tk
from tkinter import messagebox
def function():
root = tk.Tk()
returned_values = {}
entry = tk.Entry(root)
entry.pack()
button = tk.Button(root, text = "I'm a button", command=lambda: callback(entry.get(), returned_values))
button.pack()
root.mainloop()
def callback(info, returned_values):
returned_values[len(returned_values)+1] = info
messagebox.showinfo('Success', f"Mutable: {returned_values}")
function()
As you can see, returned_values persists because it is a mutable object
You can fix this problem by creating a closure for i and j with the creation of each lambda:
command = lambda i=i, j=j: update_binary_text(i, j)
You could also create a callback factory with references to the button objects themselves:
def callback_factory(button):
return lambda: button["text"] = "1"
And then in your initialization code:
for j in range(0, number):
new_button = Button(root, text=" ")
new_button.configure(command=callback_factory(new_button))
new_button.pack()
buttonList.append(new_button)
Whenever I need a collection of similar widgets, I find it's simplest to enclose them in an object and pass a bound-method as callback rather than playing tricks with lambda. So, instead of having a list like buttonList[] with widgets, create an object:
class MyButton(object):
def __init__(self, i, j):
self.i = i
self.j = j
self.button = Button(..., command = self.callback)
def callback(self):
. . .
Now, you have a list buttonList[] of these objects, rather than the widgets themselves. To update the text, either provide a method for that, or else access the member directly: buttonList[i].button.configure(. . .) And when the callback is activated, it has the entire object and whatever attributes you might need in self.
The command lambda does not take any arguments at all; furthermore there is no evt that you can catch. A lambda can refer to variables outside it; this is called a closure. Thus your button code should be:
bouton1 = Button(main_window, text="Enter",
command = lambda: get(Current_Weight, entree1))
And your get should say:
def get(loot, entree):
loot = float(entree.get())
print(loot)
Actually, you just need the Entry object entree1 as the lamda pass-in argument. Either statement below would work.
bouton1 = Button(main_window, text="Enter", command=lambda x = entree1: get(x))
bouton1 = Button(main_window, text="Enter", command=lambda : get(entree1))
with the function get defined as
def get(entree):
print(float(entree.get()))
This can be done using a lambda, like so:
button = Tk.Button(master=frame, text='press', command= lambda: action(someNumber))
This is a simple way to bind the argument without an explicit wrapper method or modifying the original action.
This can also be done by using partial from the standard library functools, like this:
from functools import partial
#(...)
action_with_arg = partial(action, arg)
button = Tk.Button(master=frame, text='press', command=action_with_arg)
I'm stuck, what am I missing?
Not sure if it's classes or tkinter that I don't correctly understand.
If I run the example below and hit the button I get "missing argument (self)". I totally get that.
class MainWidget:
root = Tk()
root.geometry("400x400")
def open_notebook(self):
self.search_function.get_emp_id()
# and more stuff to add later
search_frame = Frame(root)
search_frame.pack()
search_function = SearchFunction(search_frame)
open_notebook_button = Button(root, text="Open", command=open_notebook)
open_notebook_button.pack()
root.mainloop()Then I tried:
command=lambda: open_notebook()
... but it doesn't know open_notebook.
command=lambda: self.open_notebook()
... it doesn't know self
command=lambda: root.open_notebook()
... and it doesn't know root.
As I am playing around more with this I realize I have no idea if I maybe need a contructor and what difference exactly that would make, what goes in it (no pun intended) and what doesn't. I have no experience with OOP beyond the very very basics.
I'm grateful for any advice!