Tkinter Tic Tac Toe Drawing a shape in a certain box Tkinter Tic Tac Toe Drawing a shape in a certain box tkinter tkinter

Tkinter Tic Tac Toe Drawing a shape in a certain box


You can "discretize" the x and y values by integer-dividing and then multiplying with the width of the individual cells (and adding some offset for the center).

def drawo(event):    x2, y2 = event.x, event.y    x2 = x2 // 300 * 300 + 150    y2 = y2 // 300 * 300 + 150    ...

Same for drawx.

Alternatively, you could use different canvas elements (or buttons, labels or similar) for the different cells in the grid and get the clicked widget from the event.


You need to bind the mouse click event to canvas:

w.bind('<Button-1>', on_click)

Then determine which cell is clicked in on_click handler:

SIZE = 300player = 1  # 1 for O, 2 for Xdef on_click(event):    global m    global player    row = event.y // SIZE    col = event.x // SIZE    # check whether the cell is not filled yet    if m[row][col] == 0:        # calculate the center of the cell        cx = col * SIZE + SIZE // 2        cy = row * SIZE + SIZE // 2        # draw X or O based on current player        if player == 1:            draw_O(cx, cy)        else:            draw_X(cx, cy)        # set cell is filled        m[row][col] = player        # now you need to check whether current player wins        ...        # if no one wins, toggle player        player = 2 if player == 1 else 1def draw_O(x, y):    radius = SIZE // 3    w.create_oval(x-radius, y-radius, x+radius, y+radius, width=5, tag='cell')  # tag is used for resetting the gamedef draw_X(x, y):    radius = SIZE // 3    w.create_line(x-radius, y-radius, x+radius, y+radius, width=5, tag='cell')    w.create_line(x+radius, y-radius, x-radius, y+radius, width=5, tag='cell')

If you want to reset the game:

def reset_game():    global m    global player    # remove all 'O' and 'X'    w.delete('cell')    m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]    player = 1

For better design, put all the above logic in a class (inherited from Canvas). Then you can use instance variables instead of global variables.


To add more detail to tobias_k's answer, the below code will draw an X when the right mouse button is clicked and an O when the left mouse button is clicked.

An improvement in the code could be to use a variable to define the size of the canvas and each X/O rather than hard coding 200 or 300.

from tkinter import *ttt = Tk()ttt.title("Tic Tac Toe")w = Canvas(ttt, width = 902, height = 902)w.configure (bg =  "white")w.pack()m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]def drawx(event):    print("drawx")    x, y = event.x, event.y    x0 = x // 300 * 300 + 50    y0 = y // 300 * 300 + 50    x1 = x0 + 200    y1 = y0 + 200    #return w.create_oval(x0, y0, x1, y1)    w.create_line(x0,y0,x1,y1, fill = "black")    w.create_line(x0,y0+200,x1,y1-200, fill = "black")def drawo(event):    print("drawo")    x, y = event.x, event.y    x0 = x // 300 * 300 + 50    y0 = y // 300 * 300 + 50    x1 = x0 + 200    y1 = y0 + 200    return w.create_oval(x0, y0, x1, y1)w.create_line(0, 300, 901, 300, fill = "black") w.create_line(0, 601, 901, 601, fill = "black")w.create_line(300, 0, 300, 901, fill = "black")w.create_line(601, 0, 601, 901, fill = "black")w.bind('<Button-1>',drawo)w.bind('<Button-3>',drawx)ttt.mainloop()