pythontkinter

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


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?


Solution

  • 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.