Vindex Vindex - 7 months ago 9
Python Question

How to make a shape change in color whenever I click on it in a Connect Four board?

I have been trying to make a Connect Four game in Phyton using the tkinter toolkit. I am now on the stage of making a board. I tested if the circles will change in color whenever I click them. It turns out only the last column of the last row is changed wherever I click on the board. How can I make it in a way that whenever I click a specific circle, it will change in color? Thank you in advance for your time.

from tkinter import *
import random

def conx_create_window():
mw = Tk()
mw.title("Connect Four Game")
mw.geometry("650x600")
mw.configure(bg = "#3C3C3C", padx= 50, pady = 50)
return mw

def main():
m_window = conx_create_window()
return m_window
m_window = main()
mframe = Frame(m_window, bg = "#3C3C3C", padx = 50, pady = 150)
mframe.pack()
newframe = Frame(m_window, bg = "#3C3C3C", padx = 50, pady = 50)
board = {}
buttons = {}
frames = {}
gameBoard = Frame(m_window)
#----------------------------------
def newgame_click():
print("New game")
mframe.pack_forget()
boardOption()

def boardOption():
newframe.pack()


def board7x6():
gameBoard.pack()
newframe.pack_forget()
print("7x6 Board Size")
for row in range(6):
board[row] = {}
frames[row] = Frame(gameBoard)
frames[row].pack()
for col in range(7):
board[row][col] = 0
frame = Frame(frames[row])
frame.pack(side = LEFT)
c = Canvas(frame, bg = "#666", width = 50, height = 50)
c.pack()
r = c.create_rectangle((0, 0, 50, 50), fill= "#3C3C3C")
circle = c.create_oval(3,3,49,49, fill= "#3D3D3D")
c.tag_bind(r, '<Button-1>', lambda event: print('works'))
c.tag_bind(circle, '<Button-1>', lambda event: c.itemconfig(circle, fill = "green"))
print(" ", board[row][col], " ", end ="")

print()

def board8x7():
gameBoard.pack()
newframe.pack_forget()
print("8x7 Board Size")
for row in range(7): # 7 rows
board[row] = {}
buttons[row] = {}
frames[row] = Frame(gameBoard)
frames[row].pack()
for col in range(8): # 8 columns
board[row][col] = 0
buttons[row][col] = Button(frames[row], text = "", width = 8, height = 4, bg = "#1EC811", bd = 0, highlightthickness=0)
print(" ", board[row][col], " ", end ="")
buttons[row][col].pack(side= LEFT)
print()







board7x6_btn = Button(newframe, text = "7X6", bg = "#64E545", command = board7x6, bd = 0, highlightthickness=0)
board8x7_btn = Button(newframe, text = "8X7", bg = "#64E545", command = board8x7, bd = 0, highlightthickness=0)

board7x6_btn.grid(row = 0, column= 0, padx = 20, pady = 10, ipadx = 20, ipady = 20)
board8x7_btn.grid(row = 0, column= 1, padx = 20, pady = 10, ipadx = 20, ipady = 20)


newgame_btn = Button(mframe, text = "NEW GAME", bg = "#64E545", command = newgame_click, bd = 0, highlightthickness=0)
load_btn = Button(mframe, text = "LOAD", bg = "#64E545", padx = 25, bd = 0, highlightthickness=0)
ins_btn = Button(mframe, text = "INSTRUCTIONS", bg = "#64E545", bd = 0, highlightthickness=0)
exit_btn = Button(mframe, text = "EXIT", bg = "#64E545", padx = 10, bd = 0, highlightthickness=0)#, command = exit_click)

newgame_btn.grid(row = 0, column= 0, padx = 10, pady = 10, ipadx = 10, ipady = 20)
load_btn.grid(row = 0, column= 1, padx = 10, pady = 10, ipady = 20)
ins_btn.grid(row = 1, column= 0, padx = 10, pady = 10, ipady = 20)
exit_btn.grid(row = 1, column= 1, padx = 10, pady = 10, ipadx = 20, ipady = 20)
#----------------------------------
m_window.mainloop()

Answer

The problem is the lambda construction: c is always the same (last one) and is therefore not evaluated at execution:

c.tag_bind(circle, '<Button-1>',  lambda event: c.itemconfig(circle, fill = "green"))

Use a default argument instead::

c.tag_bind(circle, '<Button-1>',  lambda event, c=c: c.itemconfig(circle, fill = "green"))

So c is now a default argument and now you have different lamdas. See here for a far better explanation than mine.