0

I'm creating a simple TicTacToe GUI. Here is what I got so far:

import tkinter as tk  

def initTable(master, rows, columns):
    for i in range(0, columns):
        button = tk.Button(master, text="", height=1, width=2)
        button.grid(row=i)
        for j in range(0, rows):
            button2 = tk.Button(master, text="", height=1, width=2)
            button2.grid(row=i, column=j)


if "__main__" == __name__:
    print("Welcome to the TicTacToe game!")
    print("Recommended size: 10x10")
    correctinput = False
    while True:
        if correctinput:
            print("The entered size is too big, please enter a smaller value")
        height = int(input("Please enter the height (Max. 70)!"))
        width = int(input("Please enter the width (Max. 70)!"))
        correctinput = True
        if height <= 70 and width <= 70:  # This check is needed because it seems that you can't use any bigger
            # table than this, it will freeze the computer...
            break
    master = tk.Tk()
    master.resizable(width=False, height=False)
    initTable(master, height, width)
    master.mainloop()

So this creates the GUI with the width and height specified by the user. However, now I want to manage these buttons which is created seperately. For example if you press the left mouse button on a button created in the GUI it should display an X in that label. I found these to display it:

def leftclick(event):
    print("leftclick")


def rightclick(event):
    print("rightclick")

button.bind('<Button-1>', leftclick)
button.bind('<Button-3>', rightclick)

However I don't know how could I use this, because the buttons don't have unique names, etc... maybe with winfo_child()?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Kristof Rado
  • 713
  • 1
  • 8
  • 19
  • Something like this, but as you can see in the code, I don't have exact items (like l1, l2 in the example provided), so I can't bind to these buttons. I think it loses this binding after replacing it with a new button item? – Kristof Rado Apr 12 '18 at 13:44

1 Answers1

0

The first thing you have to do is to fix your initTable function. If you take a closer look you'll see that it's creating too many buttons:

def initTable(master, rows, columns):
    for i in range(0, columns):
        button = tk.Button(master, text="", height=1, width=2)
        button.grid(row=i)
        # ^ we don't need that button
        for j in range(0, rows):
            button2 = tk.Button(master, text="", height=1, width=2)
            button2.grid(row=i, column=j)

The nested loops are actually creating two layered buttons right on top of each other. The correct code creates buttons only in the inner loop:

def initTable(master, rows, columns):
    for i in range(0, columns):
        for j in range(0, rows):
            button = tk.Button(master, text="", height=1, width=2)
            button.grid(row=i, column=j)

While you're at it, you should also connect the leftclick and rightclick functions to each button that's created:

def initTable(master, rows, columns):
    for i in range(0, columns):
        for j in range(0, rows):
            button = tk.Button(master, text="", height=1, width=2)
            button.grid(row=i, column=j)
            button.bind('<Button-1>', leftclick)
            button.bind('<Button-3>', rightclick)

The callback functions have access to the button that triggered the event through the event.widget attribute, so the implementation is easy enough:

def leftclick(event):
    mark_button(event.widget, 'X')

def rightclick(event):
    mark_button(event.widget, 'O')

def mark_button(button, mark):
    # if the button has already been clicked, do nothing
    if button['text']:
        return

    button['text'] = mark
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149