1

I have created 9 buttons with a loop and want each of them to display "x" when clicked. However, the command function is not properly executing for each button.

I already tried using lambda... I think the issue might be in the way that I named each Button?

def create_buttons(self):

      buttoncounter = 1

      for i in range(9):

              self.temp_string = "b" + str(buttoncounter)

              self.temp_string = Button(self, text = "\n\t\n\t\n\t")

              self.temp_string.grid(row = (20 + i), column = (20))

              self.temp_string.configure(command=partial(self.mark_box, 
              buttoncounter))

              buttoncounter += 1


  def mark_box(self, num):

    turnlist = ["x", "o"]

    self.temp_string = "b" + str(num)

    self.temp_string.configure(text = "x")

I want to be able to click a button and have it check itself off, but when I click any of the 9 buttons it only checks off the 9th one.

Yoann Kergall
  • 2,993
  • 5
  • 22
  • 23

1 Answers1

0

To access widgets created in a loop we use dictionaries and list to keep a reference to them. Later we can modify them from their references stored inside dictionaries or list.

Like so..

all_buttons = []
for i in range(9):
    button = Button(root, .... )
    all_buttons.append(button)

When we need to get a specific button we can get it by all_buttons[0] which will gives us the instance of the Button first created in the loop.

But, if you want to give your own tag or name to refer each Button then use dictionary where key will be the name and value will be the instance to the Button.

all_buttons = {}
for i in range(9):
    button = Button(root, .... )
    all_buttons.update({ 'Button_%s'%i : button })

To refer, we use all_buttons['Button_0'] gives us the first created Button.


Now, How to pass commands to each button in a loop.

I see you're using partial from functools to pass argument to the function mark_box, we can also use lambda to get the same results without importing functools. Refer to this post for better understanding.

Here is a combined example of how to pass arguments in a loop to the callback function of Button using lambda and also keep the reference to the Button?

import tkinter as tk

root = tk.Tk()

label = tk.Label(root, text='Click the Button')
label.pack()

def update(text):
    label.config(text="Button %s is clicked"%text)

all_buttons = []
for i in range(9):
    button = tk.Button(root, text='Button %s'%i, command=lambda i=i: update(i) )
    button.pack()
    all_buttons.append(button)

print('\nThis the list containing all the buttons:\n', all_buttons)

root.mainloop()
Saad
  • 3,340
  • 2
  • 10
  • 32