I am creating on_press callbacks for button behavior objects inside a loop and for some reason all of the parameters for the partial stay the same as the parameters for the last partial created.
shortened example of creation:
(button is a class that implements button behaviour)
for button in list:
button.on_press=partial(my_func, button, button.arg1, button.arg2)
the problem is that the arguments arg1 and arg2 stay the same as the last iteration of the loop instead of being updated. so when I press the buttons (doesn't matter which one) the callback is called as if I pressed the last button.
why does this happen / how can I fix this?
Related
So I am trying to make hangman in python using Tkinter and I have mostly finished the game but, I want to add a feature that disables the button once it is pressed so that the user doesn't guess the same letter twice. Any idea how I can implement it.
the code:https://drive.google.com/file/d/1v0tjlSZC_xHCQ0WopNPRJC1pLNaQ4wRR/view?usp=sharing
Not only do you overwrite the button object when you create all the buttons, the button object will also be None because place() doesn't return anything.
Split that line in two:
button = Button(...) and
button.place(...)
But even then the button object is overwritten for each new button, so the button object takes the value of the last button 'z'.
To disable individual buttons, you need to be able to access each of them, e.g. by putting all objects in a list: button[n] = Button(...) Then in the guess() function you must disable exactly that button that was pressed.
I've created multiple buttons at runtime and stored them in a list.
keys = []
keys.append(Button(label="-- Parent --"))
for key in node_obj.children.keys():
keys.append(Button(label=key))
Note that the number of children of node_obj may vary, so the number of buttons is not always the same. I'm trying to create callbacks for all the buttons and did it like this:
def test_fn(button):
print(button.label)
for button in keys:
button.on_click(lambda : test_fn(button))
but it always prints the label of the last button in the list. How can I modify it such that the label of the button that was clicked is printed?
This is a result of the way Python works. When the lambda is actually executed it uses the value of button from the outer scope—which is the last value of the loop. You will need to use the standard library functools.partial function to "bake in" each different button ahead of time:
from functools import partial
def test_fn(button):
print(button.label)
for button in keys:
button.on_click(partial(test_fn, button=button))
I am using Tkinter and Python3.
In my application there are multiple buttons, that are calling their own functions.
Now I would like to add a function, that gets called by clicking on any button, without unbinding the functions specific to the button itself.
What I am trying to do is:
Multiple buttons have their own function:
**Button1** calls **function A**
**Button2** calls **function B**
**Button3** calls **function C**
Whenever ANY button is called, ONLY Function D is called, a timer of 10 minutes is set, and when any button is called now, it calls his own function.
The simplest way is to have all three buttons call the one function, with all the state and logic contained within that one function. Each time any button is pressed the state determines whether that press event calls function D or the appropriate function for the button pressed (A, B or C).
If you cannot arrange that then just make functions A, B and C do nothing but call function D, which arranges to execute the D code or A, B or C code depending on the state.
I am writing a program using tkinter, but I do not understand how it works. Normally, code is executed top-down, but with tkinter it obviously does not.
For example, I have bound a function to the left mouse button, and this function is executed every time I click the button. But how is the other code around that treated? My problem is that I in the start of my program initialize a variable that is used as an argument in the bound function, and then it is changed in the function and returned. But every time the function is called, the variable seems to be reset to its initial value.
Does anyone know why this is?
I have it written like this:
var = "black"
var = c.bind("<Button-1>", lambda event: func(event, arg=var))
The function "func" changes var and returns it, but the next time I press the button the variable is always "black".
Thanks in advance!
Tkinter does indeed run top down. What makes tkinter different is what happens when it gets to the bottom.
Typically, the last executable statement in a tkinter program is a call to the mainloop method of the root window. Roughtly speaking, tkinter programs look like this:
# top of the program logic
root = tkinter.Tk()
...
def some_function(): ...
...
some_widget.bind("<1>", some_function)
...
# bottom of the program logic
root.mainloop()
mainloop is just a relatively simple infinite loop. You can think of it as having the following structure:
while the_window_has_not_been_destroyed():
event = wait_for_next_event()
process_event(event)
The program is in a constant state of waiting. It waits for an event such as a button click or key click, and then processes that event. Conceptually, it processes the event by scanning a table to find if that event has been associated with the widget that caught the event. If it finds a match, it runs the command that is bound to that widget+event combination.
When you set up a binding or associate a command with a button, you are adding something to that table. You are telling tkinter "if event X happens on widget Y, run function Z".
You can't use a return result because it's not your code that is calling this function. The code that calls the function is mainloop, and it doesn't care what the function returns. Anything that gets returned is simply ignored.
I'm using Tkinter for a small Python application. It has a set of ratio buttons, a text box, and a button. Is there a way to make it so the user can simply press Enter/Return on a keyboard and run the same function the button runs? The text box stays selected even when a radio is changed, so that won't cause any problems.
You should be able to bind an event handler to either the text box widget or the whole application that will be called when the event happens. Assuming you have a function to handle the event, something along the lines of:
widget.bind('<Return>', event_handler)
You can also bind a handler function at the application level by calling the bind_all() method of any widget, e.g.:
self.bind_all('<Return>', self.event_handler)
Note the key name is Return not Enter. See Key Names for a list of them all. You can also prefix the key name with a modifier like Shift- and Control- if desired.
There's a decent online reference for tkinter 8.4 here.