Tkinter 鼠标指针无法悬停在按钮上

Tkinter mouse pointer not working for hovering over button

我在 Python Tkinter 中的鼠标指针有问题。

我有以下代码:

import tkinter as tk
root = tk.Tk()

def motion(event):
    x, y = window_canvas.canvasx(event.x), window_canvas.canvasy(event.y)
    print('{}, {}'.format(x, y))

window_canvas = tk.Canvas(root, borderwidth=0, background="white", width = 300, height = 300, highlightthickness=0)
window_canvas.pack(fill='both')
window_frame = tk.Frame(window_canvas, background='red', borderwidth=0, width = 300, height = 300)
window_frame.pack()

button = tk.Button(window_frame, text='    ', borderwidth=1, highlightbackground='#9c9c9c', bg='black')
button.place(x=50, y=50)

root.bind('<Motion>', motion)
root.mainloop()

不,我想要打印出我的鼠标相对于红框的正确坐标。但是,当我将鼠标悬停在按钮上时,坐标会发生变化,并且不再根据红色 window_frame 表示真实坐标。

有人有解决办法吗?

绑定 Motion 与根与其他小部件:

在试验了您的代码后,我做出了以下观察:

  1. Motion事件绑定到root时,(event.x, event.y)returnswindow中任意像素相对于该像素所在widget的坐标。对应widget(非root)的左上角取为(0, 0).
  2. 如果您将 Motion 事件绑定到特定的小部件,(event.x, event.y) returns 像素的坐标(相对于小部件)仅当像素存在时 直接在小部件内。如果将鼠标悬停在子窗口小部件上,则不会打印任何内容。

解决方案:

现在,来到你的问题,当鼠标悬停在按钮上时,你不能直接从 (event.x, event.y) 计算 canvas 坐标。您将必须进行以下转换。

window_coords = topleft_button_coordinates + (event.x, event.y)
canvas_coords = canvas.canvasx(window_coords.x), canvas.canvasy(window_coords.y)

只有当坐标是相对于按钮时,才必须进行上述转换。您可以使用 event.widget 属性来检查事件是否由按钮触发。

按钮左上角的坐标(相对于canvas)可以通过.winfo_x().winfo_y()获得。


工作代码:

import tkinter as tk
root = tk.Tk()

def motion(event):
    global button
    convx, convy = event.x, event.y
    if event.widget == button:
        convx, convy = button.winfo_x() + event.x, button.winfo_y() + event.y
    x, y = window_canvas.canvasx(convx), window_canvas.canvasy(convy)
    
    print('{}, {}'.format(x, y))

window_canvas = tk.Canvas(root, borderwidth=0, background="white", width = 300, height = 300, highlightthickness=0)
window_canvas.pack(fill='both')
window_frame = tk.Frame(window_canvas, background='red', borderwidth=0, width = 300, height = 300)
window_frame.pack()

button = tk.Button(window_frame, text='    ', borderwidth=1, highlightbackground='#9c9c9c', bg='black')
button.place(x=50, y=50)

root.bind('<Motion>', motion)
root.mainloop()