Вот кое-что, что очень похоже на вторую технику, упомянутую в answer @Bryan Oakley, за исключением того, что действительно связывает обработчик событий с каждым элементом холста, а не с самим виджетом Canvas
,
Чтобы обнаружить нажатия кнопок на самом виджете, которого нет ни на одном элементе в нем, сначала добавляется фоновый прямоугольный элемент, который заполняет весь холст, и ему присваивается специальный тег, который позволяет щелкать мышью, не находясь поверх других элементов. элементы на холсте, которые будут обрабатываться как особые случаи (например, вызов другой функции-обработчика события).
import tkinter as tk
import random
BKGR_TAG = '_background'
BKGR_COLOR = 'bisque'
RECT_SIZE = 50
WIDTH, HEIGHT = 400, 400
def on_click(event):
current = event.widget.find_withtag('current')
if current:
item = current[0]
tags = canvas.gettags(item)
if BKGR_TAG in tags:
msg = 'You clicked the background'
# Do other things like call event handler for whole canvas...
else:
color = canvas.itemcget(item, 'fill')
msg = 'You clicked on item with id %s (%s)' % (item, color)
label.configure(text=msg)
root = tk.Tk()
label = tk.Label(root, anchor='w')
canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT)
label.pack(side='top', fill='x')
canvas.pack(fill='both', expand=True)
# Create background rect same size as canvas.
bkgr = canvas.create_rectangle(0, 0, WIDTH, HEIGHT, width=0, fill=BKGR_COLOR,
tags=BKGR_TAG) # Marked with special tag.
canvas.tag_bind(bkgr, '<ButtonPress-1>', on_click)
for color in ('red', 'orange', 'yellow', 'green', 'blue', 'violet'):
x0 = random.randint(RECT_SIZE, WIDTH-RECT_SIZE)
y0 = random.randint(RECT_SIZE, HEIGHT-RECT_SIZE)
id = canvas.create_rectangle(x0, y0, x0+RECT_SIZE, y0+RECT_SIZE,
outline='black', fill=color)
canvas.tag_bind(id, '<ButtonPress-1>', on_click)
root.mainloop()