How to return a value from a function when it is used as a command function? How to close a user interface when a button is pressed?
At this moment you assign it to local variable filename
but if you add global filename
inside function then it will assign to global variable.
It may be good to assign to global variable some default value at start - so it will exists even if you don't select file.
If you want only filename (instead of reference to opened file) then use askopenfilename
instead of askopenfile
And if you click Cancel
then askopenfilename
should give None
and it could be better to keep it as None
instead of convert to string. And later you should check if filename
is None
to run code only if you really selected filename.
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd
filename = None # default value in global variable
# %% create a command associated to the window button
def open_file():
global filename # inform function to use global variable instead of local one
initialDir = '/'
fileTypes = (('Text files', '*.txt'), ('Csv files', '*.csv'), ('All files', '*.*'))
Title = 'Choose a file'
# use askopenfilename instead of askopenfile to get only name
filename = fd.askopenfilename(title=Title, filetypes=fileTypes)
# destroy GUI
window.destroy()
# %% create a GUI
window = tk.Tk()
window.title('Tkinter GUI Open File Dialog')
window.resizable(False, False)
window.geometry('300x150')
# %% open file button
open_button = ttk.Button(window, text='Open a File',command=open_file)
open_button.grid(column=0, row=1, sticky='w', padx=10, pady=10)
# %% run window - automatic closing after 10 seconds
window.after(10000, window.destroy)
window.mainloop()
if filename: # check if filename was really selected
print('selected:', filename)
else:
print("you didn't select filename")
If you want to keep all in function then it may need to use global
in all functions
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd
def get_filename():
global filename
filename = None # default value in global variable
# %% create a command associated to the window button
def open_file():
global filename # inform function to use global variable instead of local one
initialDir = '/'
fileTypes = (('Text files', '*.txt'), ('Csv files', '*.csv'), ('All files', '*.*'))
Title = 'Choose a file'
# use askopenfilename instead of askopenfile to get only name
filename = fd.askopenfilename(title=Title, filetypes=fileTypes)
window.destroy()
# %% create a GUI
window = tk.Tk()
window.title('Tkinter GUI Open File Dialog')
window.resizable(False, False)
window.geometry('300x150')
# %% open file button
open_button = ttk.Button(window, text='Open a File',command=open_file)
open_button.grid(column=0, row=1, sticky='w', padx=10, pady=10)
# %% run window - automatic closing after 10 seconds
window.after(10000, window.destroy)
window.mainloop()
return filename
# --- main ---
filename = get_filename()
if filename: # check if filename was really selected
print('selected:', filename)
else:
print("you didn't select filename")
Popular method is also to create main window, hide it and directly run askopenfilename
without button
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd
def get_filename():
global filename
filename = None # default value in global variable
# %% create a command associated to the window button
def open_file():
global filename # inform function to use global variable instead of local one
initialDir = '/'
fileTypes = (('Text files', '*.txt'), ('Csv files', '*.csv'), ('All files', '*.*'))
Title = 'Choose a file'
# use askopenfilename instead of askopenfile to get only name
filename = fd.askopenfilename(title=Title, filetypes=fileTypes)
window.destroy()
# %% create a GUI
window = tk.Tk()
#window.iconify() # minimize to icon
window.withdraw() # hide it
window.after(10000, window.destroy)
open_file()
window.mainloop()
return filename
# --- main ---
filename = get_filename()
if filename: # check if filename was really selected
print('selected:', filename)
else:
print("you didn't select filename")
EDIT:
Reduced version which can run with parameters
import tkinter as tk
from tkinter import filedialog
def get_filename(title='Choose a file', directory='/', file_types = (('Text files', '*.txt'), ('Csv files', '*.csv'), ('All files', '*.*'))):
window = tk.Tk()
#window.iconify() # minimize to icon
window.withdraw() # hide it
filename = filedialog.askopenfilename(title=title, initialdir=directory, filetypes=file_types)
window.destroy()
return filename
# --- main ---
filename = get_filename(directory='/')
if filename: # check if filename was really selected
print('selected:', filename)
else:
print("you didn't select filename")
Python tkinter return value from function call in a button
You can't get the return value when the function is called as the result of an event (button press, etc). The code that calls the function (inside of mainloop
) ignores the return value.
If other parts of the code need the value, you need to store it as an attribute of an object or as a global variable.
The other problem in your revised code is that you're calling the print
statement before the user has a chance to click the button, so the value will be blank even if you use a global variable. You have to wait to use the value until after you've clicked the button and selected the file.
For example, create a function that prints the value, and then attach that function to a button. Click your button to choose the file, and then click the button to display the data. As long as you save the value in the first function into a global variable, it will be available in the second function.
How to return a value of a function given as a command in tkinter
Most times, callbacks drop the return value (all tkinter
callbacks do), if any. This is because is is a bit awkward to manage return values using the observer pattern which is most often used for callbacks.
There are two main ways to transfer a value from the CB to where it is needed:
One is to use a container object
- that may be a simple python list
or dict
, or a more elaborate data class
that is accessible by the callback
, and mutated to assign the proper values to it.
here is a very simple example using a dictionary:
import tkinter as tk
def print_info():
print(f'from print_info: {information_transfer}')
def submit():
information_transfer['name'] = name_entry.get()
print(f'after input: {information_transfer}')
root=tk.Tk()
root.geometry("600x400")
name_label = tk.Label(root, text = 'Username', font=('calibre', 10, 'bold'))
name_entry = tk.Entry(root, font=('calibre', 10, 'normal'))
sub_btn = tk.Button(root,text='Submit', command=submit)
info_btn = tk.Button(root,text='print info', command=print_info)
name_label.grid(row=0, column=0)
name_entry.grid(row=0, column=1)
sub_btn.grid(row=2, column=1)
info_btn.grid(row=3, column=1)
information_transfer = {'name': None, 'other': None}
print(f'before input: {information_transfer}')
root.mainloop()
Another is the OOP approach described by @DavidGildour in another answer.
How to return a value from one function to other using a button in tkinter
From what I have understood, you are looking for something like this
from tkinter import *
def verify():
global id_
id_=id_entry.get()
if id_==ID and pass_entry.get()==PASS:
print('Success')
else:
print('Invalid')
root=Tk()
id_entry=Entry(root)
id_entry.pack()
pass_entry=Entry(root)
pass_entry.pack()
ent_button=Button(root,text='Enter',command=verify)
ent_button.pack()
ID='example'
PASS='password'
root.mainloop()
Using retrun
will be pointless in this case since callbacks can't really return anything. It has been explained well in this post.
UPDATE
If you declare the variable as global
, you can access it from anywhere in the code
def verify():
global id_
id_=id_entry.get()
if id_==ID and pass_entry.get()==PASS:
success()
else:
print('Invalid')
def success():
print(id_,'logged in successfully')
If you don't want to use global
then you can pass it to the target function
def verify():
id_=id_entry.get()
if id_==ID and pass_entry.get()==PASS:
success(id_)
else:
print('Invalid')
def success(id_):
print(id_,'logged in successfully')
How to pass a variable to a function via a Button?
The common way to do it when working with tkinter
is to use lambda
functions. The tricky part is getting the return value back because the return value of command=
functions is ignored. Folks often use global
variables to workaround that, but that tactic won't work if the function is defined in another module. Fortunately tkinter
has several type-specific container Variable
subclasses that can be passed as arguments to such functions that will permit values to be retrieved from them.
Here's runnable code showing one way of using them to do this:
script.py
from tkinter import filedialog
def load_file(input_path):
file_name = filedialog.askopenfilename(filetypes=[('EXE files', '*.exe')])
input_path.set(file_name)
def simulation(input_path, input_par): # this works fine
# the function runs an EXE file ang gives me two lists lst1 and lst2
return lst1, lst2
main.py
from script import load_file, simulation
import tkinter as tk
root = tk.Tk()
frame_file = tk.Frame(root)
frame_file.pack()
input_path = tk.StringVar()
input_var = 42
button = tk.Button(frame_file, text='Open file', command=lambda: load_file(input_path))
button.grid(row=1, column=1)
button2 = tk.Button(frame_file, text='Run simulation',
command=lambda: simulation(input_path.get(), input_var))
button2.grid(row=1, column=2)
root.mainloop()
Update
Here's a slightly more complicated but much more flexible version, that would work with many more types of return values, including user-defined classes (not just the four tkinter
supports — bool, float, int, string). Supporting more types of returned data automatically, also means that called functions don't need to be modified.
It does this by defining a CallBack
class whose instances "wrap" the functions to be called and save their return values in a tkinter StringVar
widget so they can be retrieved later as needed by calling a method get_result()
that instances of the class have. To work with more datatypes it uses Python's built-in pickle
module to temporarily store the data.
script2.py
from tkinter import filedialog
def load_file():
file_name = filedialog.askopenfilename(filetypes=[('EXE files', '*.exe')])
return file_name
def simulation(input_path, input_par): # this works fine
# the function runs an EXE file and gives me two lists lst1 and lst2
print(f'simulation({input_path=}, {input_par=}) called')
list1, list2 = ['param', input_par], list('spam')
return list1, list2
main2.py
from script2 import load_file, simulation
import pickle
import tkinter as tk
from tkinter import messagebox
class CallBack:
def __init__(self, func):
self.func = func
self.var = tk.StringVar()
def get_result(self):
pickled_result = self.var.get()
return pickle.loads(pickled_result.encode('latin1')) # Unpickle and return it.
def __call__(self):
res = self.func()
pickled_result = pickle.dumps(res).decode('latin1') # Pickle result.
self.var.set(pickled_result) # And save it in tkinter StringVar.
root = tk.Tk()
frame_file = tk.Frame(root)
frame_file.pack()
input_par = 42
callback1 = CallBack(load_file) # Wrap function from other module.
button = tk.Button(frame_file, text='Open file', command=callback1)
button.grid(row=1, column=1)
def run_sim():
""" Run simulation function and display value returned. """
# Wrap other function in other module to allow results to be retrieved.
callback2 = CallBack(lambda: simulation(callback1.get_result(), input_par))
callback2() # Call the function and save its return value.
results = callback2.get_result() # Get function's return value.
messagebox.showinfo(title='Simulation Results', message=str(results))
button2 = tk.Button(frame_file, text='Run simulation', command=run_sim)
button2.grid(row=1, column=2)
root.mainloop()
How can I return a value from an function that is executed from tkinter button?
You keep making your code more and more complicated and I still don't understand what you want.
So, I made this minimal program to show that when its the case that a new button appears, and the user presses that button, that a value is calculated and used in a call to an arbitrary function from another module:
file1.py
import tkinter as tk
def func(var):
var['file'] = 42
return var['file']
def do_something(var, f):
# root = var['root']
mainframe = var['mainframe']
bt = tk.Button(mainframe, text='submit', command=lambda: f(func(var)))
# When the user presses submit, the function f is called with the 'return' value
bt.place(relx=0.5, rely=0.5)
file2.py
import tkinter as tk
root = tk.Tk()
mainframe = tk.Frame(root, relief='raised')
mainframe.place(relx=0.1, rely=0.1, width='1100', height='380')
val = {}
val['root'] = root
val['mainframe'] = mainframe
def f(value):
print(value) # Just prints the value, but could do anything!
def chk():
import file1
file1.do_something(val, f) # f passed from here as a callback
# Note - no return value
btn = tk.Button(mainframe, text='Check', command = chk)
btn.place(relx=0.5, rely=0.8)
root.mainloop()
Note: the frame starts small and you need to drag it to resize it bigger to see the buttons.
Returning values in lambda function while using Tkinter button
Lambdas are just a shorthand notation, functionally not much different than an ordinary function defined using def
, other than allowing only a single expression
x = lambda a, b: a + b
is really equivalent to
def x(a, b):
return a + b
In the same way, what you tried to do would be no different than doing:
def x():
a, b = read_input_data()
run(a, b)
start_button = tk.Button(text = 'Start', command = x, bg = 'firebrick', fg = 'white', font = ('helvetica', 9, 'bold'))
Related Topics
How to Change Python Version in Command Prompt If I Have 2 Python Version Installed
Replace Single Quote With Double Quote in a String Python
Python Db-Api: Fetchone VS Fetchmany VS Fetchall
Check If Value from One Dataframe Exists in Another Dataframe
How to Divide Each Column of Pandas Dataframe by a Series
Key Error When Selecting Columns in Pandas Dataframe After Read_Csv
Get the Row(S) Which Have the Max Value in Groups Using Groupby
How to Check All Versions of Python Installed on Osx and Centos
Why I Get Key Error Even Though Column Present in Pandas
Pandas: How to Assign Values Based on Multiple Conditions for Existing Columns
Receiving Integers from the User Until They Enter 0
How to Remove Nan from List Python/Numpy
Python Pandas - Get Row Based on Previous Row Value
How to Divide Each Column of Pandas Dataframe by a Series
How to Kill a While Loop With a Keystroke
How to Run Two Python Scripts Simultaneously from a Master Script