0

I'm building a tic-tac-toe gui with tkinter. Each cell is a Frame and I would like to be able to focus on any of them using the mouse.

Here is what I tried:

import tkinter as tk

def on_event(event, target):
    target.focus()
    print(target)


class Example(tk.Tk):
    def __init__(self):
        super().__init__()
        self.frames = []
        self.main = tk.Frame(self, bg = "black")
        self.build_widgets()
        self.main.pack()
        
    def build_widgets(self):
        for i in range(3):
            self.frames.append([])
            for j in range(3):
                newframe = tk.Frame(self.main, bg='white', width=50, height=50,
                                    highlightcolor="blue", highlightthickness=1)
                self.frames[i].append(newframe)
                self.frames[i][j].bind("<Enter>", 
                                       lambda event : on_event(event, self.frames[i][j]))
                self.frames[i][j].grid(row=i, column=j, padx = 1, pady = 1)


Example().mainloop()

This does detect the transition from one frame to another but for some reason it seems like it only remembers the last created frame (printed as .!frame.!frame9). Why is the bottom-right cell the only one to take focus?

I thought the reason was that i = j = 2 at the end of the loops so target is self.frame[2][2] once the loops end but this doesn't seem to be the case.

Thanks in advance for any answer.

Korido
  • 3
  • 2

1 Answers1

0

You shouldn't need to pass arguments to the function. The function is passed an object which can tell you which widget received the event.

First, change your binding to this:

self.frames[i][j].bind("<Enter>", on_event)

Next, change your function to this:

def on_event(event):
    event.widget.focus()
    print(event.widget)

If you need to create widgets in a loop, and pass arguments to a binding, see the answers to tkinter creating buttons in for loop passing command arguments

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685