Я хочу привязать ключевое событие к элементу холста Python tkinter, например, к прямоугольнику. Я могу привязать ключ к самому холсту (см. пример кода, клавиша «a», «b», «c»), но не к элементу холста в виде прямоугольника (см. пример кода, клавиша «r», «с», «т»). Что я делаю неправильно?
Я пробовал таким образом, но я получаю только реакцию, когда нажимается "a", "b" или "c" в любом месте холста, но никогда, когда "r", "s" или "t" нажимается на прямоугольник:
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()
Невозможно привязать события клавиатуры к объектам холста, за исключением текстовых элементов. Из канонической документации для focus
метода холста:
«Установите фокус клавиатуры для виджета холста на элемент, заданный tagOrId. Если tagOrId ссылается на несколько элементов, то фокус устанавливается на первый такой элемент в списке отображения, который поддерживает курсор вставки. Если tagOrId не ссылается ни на один элементы, или если ни один из них не поддерживает курсор вставки, то фокус не изменяется."
Единственный элемент холста, поддерживающий курсор вставки, — это текст.
Наиболее распространенным решением является привязка к холсту (не с помощью bind_all
, а к фактическому холсту), а затем также предоставление холсту фокуса клавиатуры.
canvas_id.bind("r", rectangle_hit)
canvas.focus_set()
Затем вам решать, какой элемент холста должен получить событие. Например, вы можете использовать тег "current"
для ссылки на объект под курсором. Или вы можете реализовать свою собственную концепцию фокуса для объекта холста.
Не могли бы вы объяснить, почему нельзя использовать bind_all (в моем примере кода это сработало)?
@MatthiasSchweikart, вы можете использовать bind_all, но это именно то, что он говорит. Если фокус находится на каком-либо другом виджете, таком как запись или текстовый виджет, он все равно сработает. Если вы хотите, чтобы событие было перехвачено только тогда, когда холст имеет фокус, вам необходимо выполнить привязку к виджету.
Также убедитесь, что элемент и холст не отключены.