This question already has answers here:
How to pass an argument to event handler in tkinter?
(7 answers)
Closed 4 years ago.
I'm pulling my hair out and sure I'll be embarrassed by how simple my mistake is. I have created a Combobox which is supposed to launch a function each time is it selected. However nothing happens when you pick a different selection.
Here's the code:
acc_drop_box = ttk.Combobox(mainframe, textvariable=acc_value)
acc_drop_box['values'] = acc_list
acc_drop_box.grid(column=1, row=2, sticky=(W, E))
acc_drop_box.bind('<<ComboboxSelected>>', pick_acc(acc_value))
Right now the function "pick_acc" just prints the word "Hi!" for testing purposes. That happens once when I launch the program but not again no matter what I do. Thanks for your help!
You're giving the return of the callback as the reference as opposed to callback's reference. Replace:
acc_drop_box.bind('<<ComboboxSelected>>', pick_acc(acc_value))
with:
acc_drop_box.bind('<<ComboboxSelected>>', lambda var=acc_value: pick_acc(var))
Related
This question already has answers here:
tkinter creating buttons in for loop passing command arguments
(3 answers)
Closed last year.
I face an issue which is that my first button is using the second button's command. I have faced this logic error multiple times when trying to create buttons programmatically with different functions, is there a way to resolve this or is this a limitation to Tkinter? The gif below illustrates my issue.
import tkinter as tk
root = tk.Tk()
root.geometry("400x400")
def print_when_clicked(message):
print(message)
array = ["hi", "bye"]
for i in array:
tk.Button(root, text=i, command=lambda:print_when_clicked(i)).pack()
You have fallen in to one of the classic Python traps. The issue is that the lambda captures the i variable, NOT the value of i. So, after the loop finishes, i is bound to "bye", and both functions use it.
The trick to work around this is to use a fake default argument:
for i in array:
tk.Button(root, text=i, command=lambda i=i:print_when_clicked(i)).pack()
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 2 years ago.
i'm currently learning python/tkinter and I have two buttons working correctly but my final button is assigned to a function, which is supposed to run on click but it instead runs when the program is executed and then will not run when the button is clicked. I have looked at a couple of other threads and cannot work out why mine wont work.
Thanks a lot
def onclickSelectSheet():
test()
buttonSelectSheet = Button(topFrame, text="Select an information sheet", command=onclickSelectSheet(), bg = '#CDCDCD')
buttonSelectSheet.place(relx=0.2, rely=0.1, relwidth=0.6, relheight=0.4)
To execute a Button-command on click, you need to set the command option as follows:
Button(..., command=lambda: onclickSelectSheet(),...) # with parenthesis
OR
Button(..., command=onclickSelectSheet,...) # without parenthesis
Using parenthesis () without lambda executes the function as soon as the Button widget is defined
This question already has answers here:
Using lambda expression to connect slots in pyqt
(4 answers)
Closed 5 years ago.
Disclaimer: I've read other questions like this already (eg. this one) but didn't find a working solution for me yet (or I just don't understand them :))
When I create a lambda inside a for loop accessing data from the scope of the block I get a pylint warning (cell-var-from-loop) because of the way Python captures work. E.g:
for key, value in data.items():
button = QtGui.QPushButton('show data')
button.clicked.connect(lambda: show_data(value))
table_widget.setCellWidget(1, 1, button)
There are more questions like this but I still don't now how I systematically solve this issue. I tried to provide default values to the lambda like suggested here:
for key, value in data.items():
button = QtGui.QPushButton('show data')
button.clicked.connect(lambda v=value: show_data(v))
table_widget.setCellWidget(1, 1, button)
But when I do it like this weird things happen - while value ought to be a string in my example show_data is being called with a bool.
Am I doing something totally wrong? Should this approach work?
The clicked signal sends a checked parameter. So try:
button.clicked.connect(lambda checked, v=value: show_data(v))
This question already has answers here:
tkinter creating buttons in for loop passing command arguments
(3 answers)
Closed 6 years ago.
I am using python 3 with tkinter and I am having issues with a command I want to execute from a button. A variable number of buttons are generated, one for each visitor, and I am trying to call the function signOut from the button press whilst passing the relevent item (visitor) from the list to it.
I realise that the issue is with the for loop as by the time the button is pressed, i will == the last item in the list. How can I make it specific to the actual visitor. I can't seem to think of the solution. Any advice is appreciated.
buttonDictionary = {}
for i in range(0,len(currentVisitors)):
buttonDictionary[i] = Button(bottomFrame, text=currentVisitors[i], command=lambda: signOut(topFrame, bottomFrame, currentVisitors[i]))
buttonDictionary[i].pack()
It is my understanding that e.g. i in a lambda within a loop like this is referring to the variable i itself, not the value of the variable on each iteration, so that when the command callback is called, it will use the value of i at that moment, which as you noticed is the value on the last iteration.
One way to solve this is with a partial. partial will, in effect "freeze" the arguments at their current state in the loop and use those when calling the callback.
Try using a partial instead of a lambda like this:
from functools import partial
buttonDictionary = {}
for i in range(0,len(currentVisitors)):
buttonDictionary[i] = Button(bottomFrame, text=currentVisitors[i], command=partial(signOut, topFrame, bottomFrame, currentVisitors[i]))
buttonDictionary[i].pack()
Another way I have seen this done, but haven't tried, is to assign i to a new variable in your lambda each time:
command=lambda i=i: signOut(topFrame, bottomFrame, currentVisitors[i])
I have gotten burned bad more than once when I first started with Python by using lambdas in loops (including a case very similar to this trying to assign a callback to dynamically generated buttons in a loop). I even created a snippet that would expand to think_about_it('are you sure you want to use a lambda?') whenever I typed lambda just to remind me of the pain I caused myself with that...
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 6 months ago.
So, I'm creating a client manager software for a local club.
I'm using Python 3.5.1 and Tkinter.
Used a Notebook to nest my Frames.
On my first frame I made the form to add new clients (labels and textboxes) and an "add" button at the end.
Problem is that it executes the function associated with the button insted of onclick, and the button actually does nothing on click.
Been searching everywhere and it seems a rare problem.
Help?
From what I could decipher, as stated in comments your not setting the command properly.
If you have a function you need to set my_button = tk.Button(..., command = my_function)
If your function takes a keyword argument then you need to pass the function like so
my_button = tk.Button(...., command = lambda: function(argument))
I would try using lambda: before the command.
For instance, replace readFile(file) with lambda: readFile(file).
This will ensure an anonymous ("lambda") function with no parameters is passed, which upon execution will run the intended code. Otherwise, the function is executed once when the behavior is set, then the returned value is simply re-evaluated every time rather than the appropriate function being called.