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.
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
Im making this app that need to delay before call a function and get the return value. but because of time.sleep is freezing tkinter gui so i used tkinter.after. tkinter.after is working and diddnt frezee the window, but i cannot get a return value of a function that i've called. because after i delayed and get the returned value, i've to return it again to the other function that called this function.
i've been struggling with this, please if any of u know any solutions, help me
this is the basic example of whats going on
import tkinter as tk
from time import sleep
def getvalue():
value = "haha"
sleep(3)
return value
def printvalue():
value = getvalue()
print(value)
app = tk.Tk()
app.geometry("500x300")
button = tk.Button(app, text="print value", command=printvalue)
button.pack()
app.mainloop()Say I have a function ask_for_number() which is called when a button is pressed. It creates a Toplevel window with a label that says 'Enter a number', an Entry widget, and a button that says 'Validate' which calls a function called validate_entry. validate_entry checks if a number is entered, using
try:
int(entry.get())
except TypeError:
# handle the errorbut because this is a different function the only way to access entry that I know of is to make it global first. I can't use 'return entry' and re-use the variable in validate_entry, because return doesn't work within tkinter mainloop (callbacks don't and can't return anything). What is the 'proper' way to do it without using globals?
You could first display the combobox DataChosenForm(self).grid(row=0, column=0) without calling the ReturnData in the Application class.
Then, in the callback() method collect the choice choice = event.widget.get() and pass it to ReturnData. This would mean, however, that the LabelFrame is displayed only after a choice is made.
import tkinter as tk
from tkinter import ttk
class DataChosenForm(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
chosen = tk.LabelFrame(self, text="wybór")
chosen.grid(row=0)
self.combo = ttk.Combobox(chosen)
self.combo['values'] = ('wizz', 'ryanair', 'lot')
self.combo.grid(row=0, column=2, padx=80, pady=10)
self.combo.bind("<<ComboboxSelected>>", self.callback)
def callback(self, event=None):
choice = event.widget.get()
print(choice)
ReturnData(self, choice).grid(row=1)
class ReturnData(tk.Frame):
def __init__(self, parent, choice):
super().__init__(parent)
message_box = tk.LabelFrame(self, text="wynik")
message_box.grid(row=1)
mb = tk.Label(message_box, text=choice, anchor='nw')
mb.pack(padx=120, pady=30)
class Application(tk.Tk):
def __init__(self):
super().__init__()
self.title("program do wyszukiwania cen lotów")
self.geometry('300x200')
self.resizable(width=False, height=False)
DataChosenForm(self).grid(row=0, column=0)
if __name__ == "__main__":
app = Application()
app.mainloop()
I think @Julia has the basically the right architecture for your tkinter application, but her answer could be improved by using a tkinter Variable — because all widgets associated with one will automatically update their displayed value whenever the Variable is changed (by one of them or something else).
Here's a little documentation on Variable Classes. Note that since ttk.Combobox with have all the methods of a tk.Entry widgets, here's a bit of documentation about them (which also happens to illustrate the "pattern" of using of a StringVar in conjunction with one so it also applies to a ttk.Comboboxs).
Generally, you can tell a widget to use a tkinter Variable by specifying an instance of one as the option textvariable= keyword argument when the widget is created. You can also set the option using the partial dictionary interface most widgets support, so assignments like widget['textvariable'] = variable are another way to make use of them — the code below makes use of both of these ways.
Here's Julia's code modified to use a tk.StringVar. Note the Combobox doesn't need a callback function to bind the <<ComboboxSelected>> event to it, so all that complexity has been eliminated.
import tkinter as tk
from tkinter import ttk
class DataChosenForm(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
choice = tk.LabelFrame(self, text="wybór")
choice.grid(row=0)
self.combo = ttk.Combobox(choice)
self.combo['textvariable'] = parent.var # Use shared variable.
self.combo['values'] = ('wizzair', 'ryanair', 'lot')
self.combo.grid(row=0, column=2, padx=80, pady=10)
class ReturnData(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
message_box = tk.LabelFrame(self, text="wynik")
message_box.grid(row=1)
mb = tk.Label(message_box, textvariable=parent.var, # Use shared variable.
anchor='nw', width=20)
mb.pack(padx=120, pady=30)
class Application(tk.Tk):
def __init__(self):
super().__init__()
self.title("program do wyszukiwania cen lotów")
self.geometry('300x200')
self.resizable(width=False, height=False)
self.var = tk.StringVar(value='Dokonać wyboru') # Create shared variable.
DataChosenForm(self).grid(row=0, column=0)
ReturnData(self).grid(row=1)
if __name__ == "__main__":
app = Application()
app.mainloop()
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
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
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()
The best approach would be to make callback a method in a class:
class Asker(object):
def __init__(self):
self.name = None
def callback(self):
self.name = askopenfilename()
print self.name
ask = Asker()
Button(text='File Open', command=ask.callback).pack(fill=X)
Now, object ask persists, and ask.name is None if the callback has not executed yet, and after it has, the result of askopenfilename.
You could use a global instead but there's really no advantage in so doing so I recommend you use this class-based approach.
If you need some variable outside a function you need a global variable
name="" # if you don't call the function it'll remain empty!
def callback():
global name
name= askopenfilename()
print name