How can I bind a key-event to a Python tkinter canvas item?

Question:

I want to bind a key event to a Python tkinter canvas item, for example to a rectangle. I am able to bind a key to the canvas itself (see example code, key "a", "b", "c"), but not to a canvas-item as a rectangle (see example code, key "r", "s", "t"). What am I doing wrong?

I tried it in this way, but I get only a reaction, when "a", "b" or "c" is pressed at any place in the canvas, but never when "r", "s" or "t" is pressed over the rectangle:

import tkinter as tk

def canvas_hit(event):
    print("Canvas Hit")

def rectangle_hit(event):
    print("Rectangle Hit")

root = tk.Tk()

canvas_id = tk.Canvas(root, height=100, width=200)
rectangle = canvas_id.create_rectangle(20,20,50,50, fill="red")
canvas_id.grid()

canvas_id.bind_all("a"           , canvas_hit)
canvas_id.bind_all("<b>"         , canvas_hit)
canvas_id.bind_all("<KeyPress-c>", canvas_hit)
canvas_id.tag_bind(rectangle, "r"           , rectangle_hit)
canvas_id.tag_bind(rectangle, "<s>"         , rectangle_hit)
canvas_id.tag_bind(rectangle, "<KeyPress-t>", rectangle_hit)

root.mainloop()

Answers:

It’s not possible to bind keyboard events to canvas objects, except for text items. From the canonical documentation for the focus method of the canvas:

"Set the keyboard focus for the canvas widget to the item given by tagOrId. If tagOrId refers to several items, then the focus is set to the first such item in the display list that supports the insertion cursor. If tagOrId does not refer to any items, or if none of them support the insertion cursor, then the focus is not changed."

The only canvas item that supports the insertion cursor is text.

The most common solution is to bind to the canvas (not using bind_all but to the actual canvas), and then also giving the canvas the keyboard focus.

canvas_id.bind("r", rectangle_hit)
canvas.focus_set()

It is then up to you to decide which canvas item should receive the event. For example, you can use the tag "current" to reference the object under the cursor. Or, you could implement your own concept of focus for a canvas object.

Answered By: Bryan Oakley