This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 7 years ago.
I want to delay a function call. (Or in my mind: python is executing the function in the wrong order). In the below example i could write instead of bf(arg) the two functions bf1 and bf2 and it does work as expected: The function is called whenever the button is pressed. But if i include the arguments in the function the function call is executed only once. Returning the function itself doesn't change the behaviour.
Can you please take a look at it and give me a hint where my logic or understanding of python is wrong.
from tkinter import *
def bf(str):
print(str)
# return print(str) #alternative(same behaviour)
main=Tk(screenName='screen',baseName='base')
button1=Button(master=main,text='b1',command=bf("b1"))
button2=Button(master=main,text='b2',command=bf("b2")) # runs once (and runs here)
button1.pack()
button2.pack()
mainloop()
print('end')
--google and stackoverflow search only return things like delay function call for 1 a specific time interval This is not what i am searching for. :-(
The issue is that you are calling the function when you create the buttons, instead of passing a callable that TK will call when the button is clicked. Normally you would just pass the function itself:
button1=Button(master=main, text='b1', command=bf)
but since you want to pass arguments to bf you will need to wrap it in a lambda:
button1=Button(master=main, text='b1', command=lambda: bf('b1'))
What you do in that line is that you don't pass the function but execute it:
button1=Button(master=main,text='b1',command=bf("b1"))
You could either include only the function name, but then you can't pass a parameter to the function:
button1=Button(master=main,text='b1',command=bf)
or you could make use of lambda:
button1=Button(master=main,text='b1',command=lambda:bf("B1"))
Related
I am working through a tutorial on tkinter. I adapted some code, with the idea that every time you clicked on the button we'd create a new text label in the row below. What is confusing me is that when I write command=click it works, but when I write command = click() the function is executed a single time at the beginning of the script but not when the button is pressed. The first behaves as I'd expect. The second behaviour confuses me, as I would expect it to raise an error not perform the function once without pressing the button.
from tkinter import *
root = Tk()
position = {"Loc":1}
def click(position=position):
Label(root, text="ta").grid(row=position["Loc"], column=0)
position["Loc"] = position["Loc"] + 1
return
but = Button(root, text="click here to do nothing",command=click())
but.grid(row=0,column=0)
root.mainloop()
Note: I found the answer below more helpful than the answer to the related question here , because it made explicit that arguments are evaluated first before being passed into the function.
When you run a function in Python (like but = Button(root, text="click here to do nothing",command=click())), first all of the arguments get evaluated and then passed to the function. So, you are calling click() and then assigning its return value to the command. If it returns None or something else that Button can handle you will get no error. When you pass just click, you actually tell the function that it is supposed to call that function whenever you click the button.
Some simple code to clarify the issue:
def foo(bar):
print("\tCalling function {} from foo".format(bar))
if bar:
bar()
def fun():
print("\tExecuting fun function")
print("\nPassing function")
foo(fun)
print("\nPassing function return value")
foo(fun())
If you check out the outputs you will notice that they get executed in different order - in the second case, fun is executed first, returns None and than that None value is given to foo as a bar argument.
Passing function
Calling function <function fun at 0x000001A79F8863A0> from foo
Executing fun function
Passing function return value
Executing fun function
Calling function None from foo
As to why there is no error - why would there be?
Both are valid statements. You could have a function that returns other function and pass it to the button that way.
This question already has an answer here:
Tkinter assign button command in a for loop with lambda [duplicate]
(1 answer)
Closed 2 years ago.
Here is my code:
buttons=[]
for i in range(100):
buttons.append(Button(parent,text="0",command=lambda:[change(i)])
def change(i):
buttons[i]["text"]="1"
but as finally, the i will go to 99, I could only change the last button no matter which button I clicked. So I wonder is there any good way to do so?
The solution is very easy
Just change the command by below command
command = lambda i=i:change(i)
This will do the job for you.
Your solution not worked as expected because
python passes the last value of i
And hence to resolve this problem
The above command is the solution.
Here lambda is given argument(that is i) at the same time when each execution of loop is going and then that i
is passed to change function which is why it worked
This question already has answers here:
tkinter creating buttons in for loop passing command arguments
(3 answers)
Closed 2 years ago.
I have been trying to create multiple buttons in tkinter library (with numbers as text), using for loop. And i want to print the text of each button every time i click one. Like a calculator. But the problem is that it prints only the last line in the loop.
win=tk.Tk()
def butt(x):
print(x)
for i in range(1,4):
bt=tk.Button(win,text=i,command=lambda: butt(i));bt.pack()
win.mainloop()
One solution of this that i found is to write lambda i=i : ... but i dont understand what this is.
Thank you for your time!!
Lambda expression here returns the method that prints the i value.
import tkinter as tk
win=tk.Tk()
def get_print_method(x):
def print_i():
print(x)
return print_i
for i in range(1,4):
bt=tk.Button(win, text=i, command=get_print_method(i))
bt.pack()
win.mainloop()
Lambda in your case is an equivalent of the get_print_method function.
This a well-known behavior in Python for lambda
This happens because i is not local to the lambdas, but is defined in the outer scope, and it is accessed when the lambda is called — not when it is defined
Python FAQ on lambdas
Their solution, is to give lambda a default parameter
import tkinter as tk
win=tk.Tk()
def butt(x):
print(x)
for i in range(1,4):
bt=tk.Button(win,text=i,command=lambda j=i: butt(j))
bt.pack()
#i = 'This is now a string'
win.mainloop()
i have a question when using the Button widget in tkinter. I am new to this.
I noticed that when we use the command in the Button widget, sometimes we call a simple function just like that and sometimes we use lambda function and then we call it. What is the difference?
For example: tk.Button(window, text = "Click Me!", command = myfunction)
tk.Button(win,text="Result",command=lambda: result(en1.get())
Cant we just use it without lambda?
THank you.
Use of lambda:
The parentheses are the main reason that the function gets executed when given as command to a Button without lambda. If the function(which you are passing to the Button as a command) has no parameters(to be passed to itself), then you can simply pass it as a command avoiding the parentheses(). And hence you don't need to use lambda in this case. Like in this Example:command=func.
So using lambda is only necessary when the function has its own parameters(to be passed to itself).Like in this Example:command=lambda:func(a,b,c)
What lambda Does:
When you have to pass arguments to the function itself you have cannot avoid parentheses().
So in the case of buttons, lambda basically delays the execution of the function until the user clicks the button, by creating another function on the spot, which does not get called until the button is actually clicked. Hence the function does not get executed, where it is given as command to the Button.
Any Questions will be answered.
This question already has answers here:
How can I provide a "callback" to an API?
(5 answers)
Closed last month.
I am making a python script:
import tkinter
def print_the_nothing_thing():
print("I told you, nothing means nothing. For further assistance, please see:")
print("https://www.youtube.com/watch?v=3WNlWyFgLCg")
print("Type the url into the browser.")
#setup the window
window = tkinter.Tk()
menu = tkinter.Menu(window)
window.configure(menu=menu)
view = tkinter.Menu(menu)
file = tkinter.Menu(menu)
menu.add_cascade(label="File", menu=file)
menu.add_cascade(label="View", menu=view)
#here is my problem
view.add_command(label="Nothing here!", command=print_the_nothing_thing())
file.add_command(label="Nothing here!", command=print_the_nothing_thing())
helpm.add_command(label="Help", command=helpy())
window.mainloop()
My problem is that when I define the function, it runs the function first. After closing it, the menu command does nothing.
You need to remove () from those add_command lines, like
view.add_command(label="Nothing here!", command=print_the_nothing_thing)
file.add_command(label="Nothing here!", command=print_the_nothing_thing)
You are calling those functions there, and they return None. If you use just the name of the function, you get a function object.
You're calling the function in add_command:
view.add_command(label="Nothing here!", command=print_the_nothing_thing())
file.add_command(label="Nothing here!", command=print_the_nothing_thing())
helpm.add_command(label="Help", command=helpy())
Instead, point add_command to the function name; don't execute it.
Thus:
view.add_command(label="Nothing here!", command=print_the_nothing_thing)
file.add_command(label="Nothing here!", command=print_the_nothing_thing)
helpm.add_command(label="Help", command=helpy)