Search code examples
pythontkinterbuttondefault-arguments

Python tkinter Buttons are 'out of place' / not working properly


Hello avid python users...

I was trying to create my first GUI writing a tic-tac-toe program but I ran into a problem regarding the 9 buttons on the grid. Here is part of the code that generates the buttons:

    button = 0
    for x in range(3):
        for y in range(3):
            button = Button(root, text= " ", font=("Helvetica", 20), height=3, width=6, bg="SystemButtonFace", command=lambda button=button: b_click(button))
            button.grid(row =  x, column = y)

The click function looks like this:

    def b_click(b):
        global clicked
        if b["text"] == " " and clicked == True:
            b["text"] = "X"
            clicked = False
        elif b["text"] == " " and clicked == False:
            b["text"] = "O"
            clicked = True
        else:
            messagebox.showerror("Tic Tac Toe", "Hey! That box has already been selected \nPick another box...")

My problem is that whenever I click a button on the GUI it selects and use b_click(b) on the button to the left of whichever one I originally picked...

Help would be appreciated...


Solution

  • Look at this script:

    import tkinter as tk
    from functools import partial
    
    def b_click(button):
        button.config(text="X")
    
    root = tk.Tk()
    
    for x in range(3):
        for y in range(3):
            button = tk.Button(root, text=" ")
            command = partial(b_click, button)
            button.config(command=command)
            button.grid(row=x, column=y)
    
    root.mainloop()
    

    It uses functools.partial and <tkinter.Button>.config(...) to pass in the button to the function. From there you can do anything you like with the button.

    Edit:

    functools.partial is like a labmda but you don't need the button=button part. It takes at least 1 argument (the function name) and the rest of the arguments/key word arguments are passed to the function when it is called.

    So

    x = partial(function, arg1, arg2, kwarg1="")
    x(arg3)
    

    will be the same as function(arg1, arg2, arg3, kwarg1="text").