Home > Enterprise >  How to change a square's color with tkinter
How to change a square's color with tkinter

Time:11-06

Doing a minesweeper on python using tkinter. I'm trying to make a square white when you click on it but it only makes the first square white.

import random
import tkinter as tk
import time

def init_grille(m, n, n_mines): # Creates the grid with the mines and the numbers
    grille = []
    for i in range(m) :
        ligne = []
        for i in range(n) :
            ligne.append(0)
        grille.append(ligne)
    for i in range(n_mines) :
        rm = random.randint(0, m - 1)
        rn = random.randint(0, n - 1)
        while grille[rm][rn] == 'X' :
            rm = random.randint(0, m - 1)
            rn = random.randint(0, n - 1)
        grille[rm][rn] = 'X'
    for em in range(m) :
        for en in range(n) :
            if grille[em][en] == 0 :
                m_proches = 0
                if en > 0 and grille[em][en-1] == 'X' :
                    m_proches  = 1
                if en < n - 1 and grille[em][en 1] == 'X' :
                    m_proches  = 1
                if em < m - 1 and grille[em 1][en] == 'X' :
                    m_proches  = 1
                if em < m - 1 and en < n - 1 and grille[em 1][en 1] == 'X' :
                    m_proches  = 1
                if em < m - 1 and en > 0 and grille[em 1][en-1] == 'X' :
                    m_proches  = 1
                if em > 0 and grille[em-1][en] == 'X' :
                    m_proches  = 1
                if em > 0 and en < n - 1 and grille[em-1][en 1] == 'X' :
                    m_proches  = 1
                if em > 0 and en > 0 and grille[em-1][en-1] == 'X' :
                    m_proches  = 1
                grille[em][en] = m_proches
    return grille

def init_grille_joueur(m, n): # Creates the grid the player interacts with (digging and flagging)
    grille_j = []
    for i in range(m) :
        ligne = []
        for i in range(n) :
            ligne.append(0)
        grille_j.append(ligne)
    return grille_j

root = tk.Tk()
M = 10
N = 10
LARGEUR_CASE = 50
HAUTEUR_CASE = 50 # Just some values used for testing the program

def fenetre_principale(): # Configurates the window
    label = tk.Label(root, text = "GO !", background = "white")
    label.pack()
    root.title("Démineur")
    root.geometry(str(M * LARGEUR_CASE)   'x'   str(N * HAUTEUR_CASE   90))

def init_canvas(m, n): # Creates the visual grid
    rect_id = []
    canvas = tk.Canvas(root, width = M * LARGEUR_CASE   25, height = N * HAUTEUR_CASE   25)
    for i in range(m):
        for j in range(n):
            rect_id.append(canvas.create_rectangle(j * LARGEUR_CASE, i * HAUTEUR_CASE, (j   1) * LARGEUR_CASE, (i   1) * HAUTEUR_CASE, outline = "lightgray", fill = "gray", width = 2))
    canvas.bind('<Button-1>', clic_gauche)
    canvas.bind('<Button-3>', clic_droit)
    canvas.pack()
    return rect_id, canvas

def get_case(x, y): # Locates a square on the visual grid
    case = canvas.find_overlapping(x, y, x, y)
    if len(case) == 0 :
        return -1, -1
    else :
        x = (case[0] - 1) // M
        y = (case[0] - 1) % N
        return x, y

def creuser(i, j): # The digging mechanic
    if not grille[i][j] == -1 :
        grille_j[i][j] = -1
        C = (j * LARGEUR_CASE   LARGEUR_CASE / 2, i * HAUTEUR_CASE   HAUTEUR_CASE / 2)
        case_id = canvas.find_overlapping(j, i, j, i)
        case = case_id[0]
        canvas.itemconfig(case, fill = "white")
        if grille[i][j] == 'X' :
            print("Perdu!")
            canvas.create_text(C, font = "Wingdings 20 bold", text = chr(77), fill = "purple")
        elif grille[i][j] == 1 :
            canvas.create_text(C, font = "Arial 20 bold", text = str(grille[i][j]), fill = "blue")
        elif grille[i][j] == 2 :
            canvas.create_text(C, font = "Arial 20 bold", text = str(grille[i][j]), fill = "green")
        elif grille[i][j] > 2 :
            canvas.create_text(C, font = "Arial 20 bold", text = str(grille[i][j]), fill = "red")
    canvas.pack()
    
def clic_gauche(event): # Left click
    x, y = get_case(event.x, event.y)
    creuser(x, y)
    
def drapeau(i, j): # The flag mechanic, unfinished
    C = (j * LARGEUR_CASE   LARGEUR_CASE / 2, i * HAUTEUR_CASE   HAUTEUR_CASE / 2)
    if grille_j[i][j] == 0 :
        grille_j[i][j] = 1
        canvas.create_text(C, font = "Wingdings 20 bold", text = chr(80), fill = "orange")
    elif grille_j[i][j] == 1 :
        grille_j[i][j] = 0
        canvas.delete()
        
def clic_droit(event): # Right click
    x, y = get_case(event.x, event.y)
    drapeau(x, y)
    
'''def maj_labels():''' # Not finished yet

grille = init_grille(M, N, 5)
grille_j = init_grille_joueur(M, N)
fenetre_principale()
rect_id, canvas = init_canvas(M, N)
'''root.after(500, maj_labels)''' # It's supposed to update the timer which isn't implemented yet
root.mainloop()

I tried using find_overlapping to get the square's id when I click on it and then change its color with itemconfig, I tried to change the lines' order to see if they contradicted eachother but it's still the same problem

CodePudding user response:

You passed incorrect region (j, i, j, i) to canvas.find_overlapping() inside creuser(), region (*C, *C) should be used instead:

def creuser(i, j):
    ...
    #case_id = canvas.find_overlapping(j, i, j, i) # incorrect region
    case_id = canvas.find_overlapping(*C, *C) # correct region
    ...
  • Related