2

I am making a simple program that creates a 3x3 matrix of tkinter.Button() and when a button is pressed it should display the "Clicked" text on it. But the result seems like buttons that lie on the same column get bound to the same command - the one that targets the button of the last row of that column.

from tkinter import *

root = Tk()

text = [[None]*3]*3
buttons = [[None]*3]*3

def action(i, j):
    text[i][j].set('Clicked')

for i in range(3):
    for j in range(3):
        text[i][j] = StringVar()
        text[i][j].set('(%d, %d)' % (i,j))
        buttons[i][j] = Button(root, command = lambda i=i, j=j : action(i, j))
        buttons[i][j].config(textvariable = text[i][j], width = 9, height = 5)
        buttons[i][j].grid(row = i, column = j)

root.mainloop()

Image here

1 Answer 1

3

The problem is not in your commands, but in the way you create your lists.

When you multiply a list, you actually multiply a reference to this single list (see this question). You can see this when running the following code:

text = [[None]*3]*3
print([id(x) for x in text])

So when you change an item in one of the lists, the item is changed in all lists. Therefore your list doesn't look like [[1,2,3],[4,5,6],[7,8,9]], but like [[7,8,9],[7,8,9],[7,8,9]]. Then, when you think you set StringVar number 1, you actually set Stringvar number 7 so button number 7 is changed.

You can create three separate lists by using list comprehension instead of multiplication. As you can see with the following code, this produces three separate lists.

text = [[None]*3 for _ in range(3)]
print([id(x) for x in text])
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.