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?
Nothing is wrong with your code. But your understanding is not exact:
When you run this line: print(onclick2()) you are trying to print the content of the entry widget which is empty when the program first starts. So that is perfectly normal you are not getting anything visible on the Terminal.
To see the content of the entry widget, modify slightly your callback as follows:
def onclick2():
val = box.get()
print(val)
# You can remove "return val" as it is completely useless for your context
With this simple change, you will see None printed on the Terminal, which thing corresponds to what I described above. Now type something within the entry widget and click on the button: what you type appears finally on the output (Terminal).
You are trying to print the content of your entry widget but you are using the variable for your entry to receive the content which is wrong. Also call print the content in your entry widget to the your terminal .
from tkinter import *
def onclick2():
val = boss.get()
print(val)
root = Tk()
boss = StringVar() # to receive the content in the entry
box = Entry(root , textvariable=boss)
box.pack()
buttonfortxtbox = Button(root, text="Check Result", font=('Cooper Black',
9), bd=10, width=20,command=onclick2)
buttonfortxtbox.pack(anchor = S)
#print(onclick2()) # don't need to call this
root.mainloop()
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