Is there a way to identify a specific pressed button created in a list? (tkinter) [duplicate]

I have created a variable-length list containing several buttons:

buttonList = [tk.Button(command=record,
                        text=str((i % MONTH_LEN[TIME.month]) + 1))
              for i in range(x)]

x is the length of the list of buttons (PREDEFINED!).

MONTH_LEN and TIME.MONTH shouldn’t be needed of course; they’re just part of the text.

I want to be able to differentiate between the different buttons being clicked WITHOUT needing to create masses of functions.

The most important part to note is that record should change a character in a string based on which button was clicked; the first button changes the first element in the string, the 20th button changes the 20th element in the string etc etc.

How can I achieve this? Is there a better way to go about this?

  • One option is functools.partial to create function wrappers containing the current i value (record must then be adjusted to accept the additional i argument).

    – 

  • Well yes you can, easiest solution with multiple examples on the web is to use a lambda function that’s passing an argument to your function.

    – 

  • Can you explain in baby terms? Functools is a new environment to me. Also, what would ‘record’ need to be adjusted to? Thanks for your help. @MichaelButscher

    – 




  • @Thingamabobs do you mean passing ‘i’ as an argument, then using it to change the specific element? If so, I’ll make sure to give it a go. Thanks! 🙂

    – 

  • Yes, especially you can use “i” as index for your list, in case you need to address the button.

    – 

Use lambda functions

Here is an example:

import tkinter as tk

root = tk.Tk()

x = 20

my_list = ['a'] * x

def record(index):
    my_list[index] = 'b'
    print(''.join(my_list))

buttonList = [
    tk.Button(
        command=lambda index=i: record(index),
        text=str(i),
        )
    for i in range(x)
    ]

for button in buttonList:
    button.pack()

root.mainloop()

lambdas are a way to create “masses of functions” (as you put it) on the fly, without needing to give them names. The code lambda index=i: record(index) is pretty much equivalent to the following code:

def noname(index=i):
    return record(index)

Note that we have to create a keyword argument index and set its default value to i in order to “capture” the value of i at each loop iteration. If we instead did lambda: record(i), it would look up the value of i in the global scope, which will be equal to its value on the last iteration.

Errata

record should change a character in a string based on which button was clicked

Python strings are not mutable, unlike in many other languages. You cannot change them element-by-element. Actually, you cannot change them at all. You have to use a mutable container like list, and convert it to a string, as I did in my example.

Also, consider renaming buttonList to button_list. Using underscores is the convention in Python. You can read more about variable naming in PEP8.

Leave a Comment