'tkinter 2d button list command not working
I recently got back into using Python 3's tkinter and am working on some simple problems. I am working on creating a Tic Tac Toe program, but I am running into an issue. I am using a 2d list of buttons to call a command function when they are clicked. I have used partial to run functions with parameters previously. The program does use command functions correctly. Why is the command not executing when the buttons in the 2d list are clicked on?
from tkinter import *
import tkinter as tk
from functools import partial
class App(tk.Tk):
def __init__(self):
super().__init__()
pixel = tk.PhotoImage(width=1, height=1)
# configure the root window
self.title('Tic Tac Toe')
self.geometry('500x500')
self.turn=0
self.options=["X","O"]
# label
self.label = tk.Label(self, text='Tic Tac Toe')
self.label.config(font="Calibri 48")
self.label.pack()
self.gameframe=Frame(self)
self.gameframe.pack()
self.buttons=[[Button for i in range(3)] for j in range(3)]
#The main issue with the code
for i in range(3):
for j in range(3):
#self.buttons[i][j]['command'] = self.hello
buttonfunction = partial(self.clickbutton, i, j)
self.buttons[i][j]=Button(self.gameframe,image=pixel)
self.buttons[i][j].config(command= buttonfunction)
self.buttons[i][j].config(width=100,height=100)
self.buttons[i][j].grid(row=i,column=j)
print(self.buttons)
self.button = Button(self, text='Test')
self.button['command'] = self.hello
self.button.pack()
def hello(self):
print("Hello")
def clickbutton(self,x,y):
print(x,y)
buttontext=self.options[self.turn]
self.buttons[y][x].config(text=buttontext)
self.turn=(self.turn+1)%2
if __name__ == "__main__":
app = App()
app.mainloop()
Solution 1:[1]
This is one of the class tkinter blunders. The ISSUE here is that pixel is local to the __init__ function, and the Button class doesn't grab a reference. When the function ends, that image is destroyed, the button becomes invalid and no longer responds.
Use:
self.pixel = tk.PhotoImage(width=1, height=1)
...
image = self.pixel,
and things work better. You may need to specify compound='c' if you want both text and image.
And Paul M. is right, you need to change your button function to
buttonfunction = partial(self.clickButton, j, i)
to get the rows and columns right. Here's the code I have, which works:
for i in range(3):
for j in range(3):
buttonfunction = partial(self.clickbutton, j, i)
self.buttons[i][j]=Button(self.gameframe,
image=self.pixel,
text = '--',
compound='c',
width=100,
height=100,
command=buttonfunction)
self.buttons[i][j].grid(row=i,column=j)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Tim Roberts |
