Python/Tkinter - Identify object on click Python/Tkinter - Identify object on click tkinter tkinter

Python/Tkinter - Identify object on click


Here are three common solutions to this problem:

Using the item type

You can ask the canvas for the type of the object:

item_type = cv.type(item)if item_type == "rectangle":    # this item is a rectangleelse:    # this item is NOT a rectangle

Using tags

Another solution is to give each item one or more tags. You can then query the tags for the current item.

First, include one or more tags on the items you want to be clickable:

cv. create_rectangle(80, 80, 100, 100, tags=("clickable",))

Next, check for the tags on the item you're curious about, and check to see if your tag is in the set of tags for that item:

tags = cv.itemcget(item, "tags")if "clickable" in tags:    # this item has the "clickable" tagelse:    # this item does NOT have the "clickable" tag

Create bindings on tags

A third option is to attach the bindings to the tags rather than the canvas as a whole. When you do this, your function will only be called when you click on item with the given tag, eliminating the need to do any sort of runtime check:

cv.tag_bind("clickable", "<1>", onclick)


The solution of BPL is fine. Here is another solution that doesn't require any global variable. There's a system of tags in Tkinter which could be compared with "class" from HTML/CSS. It enables us to associate a list of tags to a graphic object. See item specifiers.

Here is how it would be:

import tkinter as tkdef onclick(event):    global rectangles    item = cv.find_closest(event.x, event.y)    if 'rect' in cv.gettags(item):        current_color = cv.itemcget(item, 'fill')        if current_color == 'black':            cv.itemconfig(item, fill='white')        else:            cv.itemconfig(item, fill='black')rectangles = []root = tk.Tk()cv = tk.Canvas(root, height=800, width=800)cv.pack()cv.bind('<Button-1>', onclick)id_a = cv.create_line(50, 50, 60, 60, width=2)id_b = cv.create_rectangle(80, 80, 100, 100, tags=('rect'))root.mainloop()

I think it's a bit more object oriented in some way. ;)


What about this solution:

import tkinter as tkdef onclick(event):    global rectangles    item = cv.find_closest(event.x, event.y)    if item[0] in rectangles:        current_color = cv.itemcget(item, 'fill')        if current_color == 'black':            cv.itemconfig(item, fill='white')        else:            cv.itemconfig(item, fill='black')rectangles = []root = tk.Tk()cv = tk.Canvas(root, height=800, width=800)cv.pack()cv.bind('<Button-1>', onclick)id_a = cv.create_line(50, 50, 60, 60, width=2)id_b = cv.create_rectangle(80, 80, 100, 100)rectangles.append(id_b)root.mainloop()

The main idea of this is you add the items id you want to change color to a global array (global variables are discouraged though). Then when you click with the mouse, the itemcget function will give you the id from the closest item, so you need to check whether this id is inside of the array of your rectangle items.