Mouse pos not lining up with grid

Question:

This is my 2nd/3rd time making an array backed grid in pygame, that changes cell colour on click. However, despite using my previous code, I have been unable to figure out why my current code is not working.

The problem I am facing is that, when I click a cell on the grid, a totally different cell gets coloured and I cannot work out why or what the relation to these unexpected cells is. (I think it potentially seems to be that the coloured cell matches with what the grid coords are, but the mouse pos does not align to the correct grid coord (not confirmed))

For reference, ‘pxl_size’ is the height and width of a cell and ‘pxls_width’/’pxls_height’ is how many cells make up the width of the window.

My click detection code:

elif event.type == pygame.MOUSEBUTTONDOWN:
            column = mouse_pos[0] // (self.pixel_size + pixel_margin)
            row = mouse_pos[1] // (self.pixel_size + pixel_margin)

            print(row, column)
            if self.canvas.grid[row][column] != 1:
                self.canvas.grid[row][column] = 1
                colour = black
            
                self.canvas.update_pixel(row, column, colour)

My grid code:

class Canvas():
def __init__(self, pixel_size, screen):
    self.screen = screen

    self.pxl_size = pixel_size
    self.pxls_width = int(round(screen_width/self.pxl_size, 0))
    self.pxls_height = int(round(screen_height/self.pxl_size, 0))

    self.generate_canvas()

def generate_canvas(self):
    #Logical grid
    self.grid = []
    for row in range(self.pxls_height):
        self.grid.append([]) 
        for column in range(self.pxls_width):
            self.grid[row].append(0)

    self.canvas_surface = pygame.Surface((screen_width, screen_height))
    self.canvas_surface.fill(grey)

    #Visual grid
    for row in range (self.pxls_height):
        for column in range (self.pxls_width):
            self.update_pixel(row, column, white)
    
def update_pixel(self, row, column, colour):
    pygame.draw.rect(self.canvas_surface, colour, [(pixel_margin + self.pxl_size) * column + pixel_margin, 
                            (pixel_margin + self.pxl_size) * row + pixel_margin,
                            self.pxl_size,
                            self.pxl_size])

    self.screen.blit(self.canvas_surface, (0, 0))
    pygame.display.update()

Edit (additional info):

def __init__(self):
    global mouse_pos
    mouse_pos = pygame.mouse.get_pos()

    screen.fill(grey)
    self.pixel_size = 12
    
    self.canvas = Canvas(self.pixel_size, screen)
Asked By: Kiana

||

Answers:

You must determine the mouse position each time the button is clicked.
The MOUSEBUTTONDOWN event has an attribute pos that specifies the position of the click:

for event in event_list:
    # [...]

    elif event.type == pygame.MOUSEBUTTONDOWN:
        column = event.pos[0] // (self.canvas.pxl_size + pixel_margin)
        row =    event.pos[1] // (self.canvas.pxl_size + pixel_margin)

        if self.canvas.grid[row][column] != 1:
            self.canvas.grid[row][column] = 1
            self.canvas.update_pixel(row, column, black)
Answered By: Rabbid76