Python - return from Tkinter callback

How can I get the returned object (or a variable or something else - they are all basically the same, right) from a function that runs as a Tkinter callback?

import Tkinter as Tk from functools import partial def square(x): return x*x root = Tk.Tk() var = Tk.IntVar(root, value=0) #the variable the gets passed to the class call menu = Tk.OptionMenu(root, var, *[0,1,2,3,4,5]) #a drop-down list to choose a value for the variable menu.pack() button = Tk.Button(root, text='click', command = partial(square,var.get())) #a button that calls the class button.pack() root.mainloop() 

Obviously, this is a simplified example. In fact, the function called by the button returns the objects that I want to add to the list of objects that will be stored in the main Python namespace for further operations.

In any case, here the user can select the argument for the function using the GUI and press the button that will execute the function. However, the return value of the function seems doomed to be lost for ether, as the callback will not accept returns. Can this be overcome without using the ugly global in the definition of square(x) ?

+4
source share
3 answers

The concept of "returning" values ​​from callbacks does not make sense in the context of an event-driven program. Callbacks are called as a result of the event, so there is no need to return a value there.

Generally, your callbacks should always call a function, not use functools.partial or lambda . These two are great when necessary, but if you use an object-oriented coding style, they are often unnecessary and lead to code that is harder to maintain than it should be.

For instance:

 def compute(): value = var.get() result = square(value) list_of_results.append(result) button = Tk.Button(root, text='click', command = compute) ... 

It gets a lot 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) 
+8
source

Sorry to be 6 years late, but I recently came up with a good way to do this without making your code dirty and hard to maintain. This is pretty much what DaveTheScientist said, but I just want to expand it a bit. Usually, in Tkinter, if you want a button to call a function, you do the following:

 exampleButton = Button(root, text = 'Example', command = someFunc) 

This will just call someFunc whenever a 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 starts someFunc and uses the variables arg1 and arg2 as arguments for this function. Now, what could you do in a program where many times you need functions launched by buttons to return values, creates a new function that is called by each button.

This function executes the function that you want your button to run as the first argument, and then the function arguments.

 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 this function (in this case someFunc ) and save the return value in the value variable. This also has the advantage that you can use as many arguments as you want for the function that your button launches.

+2
source

Just create the actual function that your button calls, instead of putting it in a line like this.

button=Tk.Button(parent, text='click', command=someFxn)

def someFxn(): your code

Then in your function just call var.get (), do your calculation, and then do something with the value.

0
source

All Articles