我已经知道您可以将键绑定到小部件,或者将鼠标单击绑定到画布上的元素(例如:矩形、线条等),后者的示例如下:

import tkinter as tk


class App:
    def __init__(self, master):
        self.master = master
        self.canvas = tk.Canvas(master, width=400, height=400)
        self.canvas.pack()

        # Create the main rectangle
        self.rect = self.canvas.create_rectangle(100, 100, 300, 300, fill="white", outline="black")

        # Create the three small rectangles inside the main rectangle
        self.rect1 = self.canvas.create_rectangle(120, 120, 180, 180, fill="white", outline="black", tags="button1")
        self.rect2 = self.canvas.create_rectangle(220, 120, 280, 180, fill="white", outline="black", tags="button2")
        self.rect3 = self.canvas.create_rectangle(170, 220, 230, 280, fill="white", outline="black", tags="button3")

        # Bind the buttons to the click event and call the hover function
        self.canvas.tag_bind("button1", "<Button-1>", lambda event, tag="button1": self.button_click(event, tag))
        self.canvas.tag_bind("button2", "<Button-1>", lambda event, tag="button2": self.button_click(event, tag))
        self.canvas.tag_bind("button3", "<Button-1>", lambda event, tag="button3": self.button_click(event, tag))

        self.canvas.tag_bind("button1", "<Enter>", lambda event, tag="button1": self.hover(event, tag))
        self.canvas.tag_bind("button2", "<Enter>", lambda event, tag="button2": self.hover(event, tag))
        self.canvas.tag_bind("button3", "<Enter>", lambda event, tag="button3": self.hover(event, tag))

        self.canvas.tag_bind("button1", "<Leave>", lambda event, tag="button1": self.leave(event, tag))
        self.canvas.tag_bind("button2", "<Leave>", lambda event, tag="button2": self.leave(event, tag))
        self.canvas.tag_bind("button3", "<Leave>", lambda event, tag="button3": self.leave(event, tag))

    def button_click(self, event, tag):
        # Get the coordinates of the clicked rectangle
        x1, y1, x2, y2 = self.canvas.coords(tag)

        # Create a grey rectangle around the clicked rectangle
        self.canvas.delete("clicked")
        self.canvas.create_rectangle(x1 - 5, y1 - 5, x2 + 5, y2 + 5, outline="grey", fill="grey", tags="clicked")

    def hover(self, event, tag):
        # Get the coordinates of the hovered rectangle
        x1, y1, x2, y2 = self.canvas.coords(tag)

        # Create a grey rectangle around the hovered rectangle
        self.canvas.create_rectangle(x1 - 5, y1 - 5, x2 + 5, y2 + 5, outline="grey", tags="hover")

    def leave(self, event, tag):
        # Remove the grey rectangle when the mouse leaves the rectangle
        self.canvas.delete("hover")


root = tk.Tk()
app = App(root)
root.mainloop()

上面的方法适用于将鼠标点击绑定到一个矩形.但后来我注意到,如果我用<KeyPress><Key>或特定的键替换<Button-1>,例如<BackSpace>,它实际上并不起作用.

我一开始以为这是因为没有对准焦点而不起作用,所以我试着使用canvas.focus_set(),但只有当我使用<Enter><Leave>时才有效,而使用canvas.tag_bind:

import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, width=200, height=200)
canvas.pack()

canvas.create_line(10, 10, 100, 100, tags="mytag")

canvas.create_line(10, 20, 100, 80, tags="mytag")

canvas.create_oval(50, 50, 60, 60, fill="black", tags="mytag")

canvas.create_oval(50, 80, 70, 90, fill="blue", tags="no")



canvas.tag_bind("mytag", "<Enter>", lambda event: print("entered element with mytag"))
canvas.tag_bind("mytag", "<Leave>", lambda event: print("leaving element with mytag"))

root.mainloop()

将鼠标悬停在元素上,除了蓝点,似乎是有效的.我发现对绑定键有效的唯一方法是在使用上面的bind_all键时:

def on_keypress(event):
    element_ids = canvas.find_withtag("current")
    if element_ids:
        print("Key pressed over element:", element_ids)

canvas.tag_bind("mytag", "<Enter>", lambda event: canvas.focus_set())
canvas.tag_bind("mytag", "<Leave>", lambda event: root.focus_set())
canvas.bind_all("<KeyPress>", on_keypress)

编辑:看起来用canvas.bind代替canvas.bind_all也行.

但这并不理想,因为我想将单个键绑定到单个"组"元素(例如:它们都共享相同的标签).

除了我自己的非工作try 之外,还有什么方法可以做到这一点吗?

推荐答案

绑定到KeyEvent的条件已经被聚焦.聚焦画布使画布能够为此类事件提供支持.画布本身有一个完全独立的焦点,可以赋予支持插入光标的项目.唯一支持插入光标的项类型是text项.This is documented in the section focus of the Canvas widget,其中:

将画布小部件的键盘焦点设置为 TAGORID.如果tag OrId引用多个项,则焦点设置为 显示列表中支持插入的第一个此类项目 光标.如果tag OrID没有引用任何项,或者如果没有引用任何项 支持插入光标,则焦点不变.如果 为空字符串,则重置焦点项目,以便没有 项目有焦点.如果未指定tag OrID,则命令 返回当前具有焦点的项的id,否则返回空 如果没有具有焦点的项,则为字符串.

将焦点设置到某项后,该项将显示 插入光标和所有键盘事件都将定向到该 项目.画布中的焦点项和 屏幕(使用焦点命令设置)是完全独立的:给定 项实际上没有输入焦点,除非(A)其画布是 焦点窗口和(B)该项目是画布内的焦点项目. 在大多数情况下,建议在Focus小部件命令之后使用 用于将焦点窗口设置为画布的焦点命令(如果不是 已经有了).

import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, width=200, height=200)
canvas.pack()

canvas.create_line(10, 10, 100, 100, tags="mytag")
canvas.create_line(10, 20, 100, 80, tags="mytag")
canvas.create_oval(50, 50, 60, 60, fill="black", tags="mytag")
canvas.create_oval(50, 80, 70, 90, fill="blue", tags="no")
canvas.create_text(100,100, text='hello', tags="mytag")

def on_keypress(event):
    canvas.focus_set()
    element_ids = canvas.find_withtag("current")
    canvas.focus(element_ids)
    if element_ids:
        print("Key pressed over element:", element_ids)

canvas.tag_bind("mytag", "<Enter>", on_keypress)
canvas.tag_bind("mytag", "<Leave>", lambda event: root.focus_set())
canvas.tag_bind("mytag", "<KeyPress>", lambda e:print(e))

root.mainloop()

Python相关问答推荐

有什么方法可以避免使用许多if陈述

如何在BeautifulSoup中链接Find()方法并处理无?

Python 约束无法解决n皇后之谜

如何从具有不同len的列表字典中创建摘要表?

聚合具有重复元素的Python字典列表,并添加具有重复元素数量的新键

在线条上绘制表面

使用setuptools pyproject.toml和自定义目录树构建PyPi包

删除字符串中第一次出现单词后的所有内容

在含噪声的3D点网格中识别4连通点模式

使用NeuralProphet绘制置信区间时出错

Django RawSQL注释字段

名为__main__. py的Python模块在导入时不运行'

在单次扫描中创建列表

Geopandas未返回正确的缓冲区(单位:米)

如何找出Pandas 图中的连续空值(NaN)?

Polars map_使用多处理对UDF进行批处理

计算机找不到已安装的库'

在Django中重命名我的表后,旧表中的项目不会被移动或删除

简单 torch 模型测试:ModuleNotFoundError:没有名为';Ultralytics.yolo';

设置索引值每隔17行左右更改的索引