Home > front end >  How to find which Canvas item is closer to the point clicked in tkinter?
How to find which Canvas item is closer to the point clicked in tkinter?

Time:04-12

I want to find which Canvas item is closer to the point I clicked. I am trying to use find the closest but I can't use it efficiently. I am trying to make an itemlist and then find which item is the closest in the itemlist. I also have self keywords since I'm trying to do all this using classes

def initUI(self):
    self.canvas = Canvas(self.parent)
    self.item1 = self.canvas.create_oval(50, 50, 60, 60, fill="red")
    self.item2 = self.canvas.create_oval(100, 100, 110, 110, fill="red")
    self.item3 = self.canvas.create_oval(150, 150, 160, 160, fill="red")
    self.itemlist = []
    self.itemlist.append(self.item1)
    self.itemlist.append(self.item2)
    self.itemlist.append(self.item3)
    print(self.itemlist) 
    self.canvas.pack()
    self.canvas.bind("<Button-1>", self.find_closest)

def find_closest(self, event):
""" """

CodePudding user response:

As pointed out in the comments you can use the Canvas method find_closest() to do what's needed. Below is a runnable example of doing that based on the code in your question. It uses an auxilary dictionary to map the ids of the canvas object to arbitrary strings (referred to as "names" in the example).

import tkinter as tk
from tkinter.constants import *

class MyClass:
    def __init__(self, parent):
        self.parent = parent
        self.initUI()

    def initUI(self):
        self.canvas = tk.Canvas(self.parent)
        self.canvas.pack()
        self.canvas.bind("<Button-1>", self.find_closest)

       # Create dictionary mapping canvas object ids to a name.
        self.object_names = {}
        id = self.canvas.create_oval(50, 50, 60, 60, fill="Red")
        self.object_names[id] = 'Red object'
        id = self.canvas.create_oval(100, 100, 110, 110, fill="Blue")
        self.object_names[id] = 'Blue object'
        id = self.canvas.create_oval(150, 150, 160, 160, fill="Green")
        self.object_names[id] = 'Green object'

        self.name_lbl1 = tk.Label(self.parent, text='Closest object:')
        self.name_lbl1.pack(side=LEFT)

        self.name_var = tk.StringVar(value='')
        self.name_lbl2 = tk.Label(self.parent, textvariable=self.name_var)
        self.name_lbl2.pack(side=LEFT)

    def find_closest(self, event):
        if (closest := self.canvas.find_closest(event.x, event.y)):
            obj_id = closest[0]
            self.name_var.set(self.object_names[obj_id])  # Updates lbl2.

if __name__ == '__main__':
    root = tk.Tk()
    instance = MyClass(root)
    root.mainloop()

Screenshot of it running:

Screenshot

  • Related