Tkinter Button跟随光标中心时闪烁问题的修复咨询
Tkinter跟随光标中心的按钮闪烁跳动问题
原代码
from tkinter import * root=Tk() root.geometry('450x500') root.config(bg='#deeffa') def follow(parent): root.bind('<Motion>',lambda event,parent=parent:center_mouser(event,parent)) parent.but.config(command=stop) def stop(): root.unbind('<Motion>') def center_mouser(event,parent): root.config(cursor="none") parent.but.place(x=event.x,y=event.y, anchor='center') class moving_but(): def __init__(self,but=None,val=0): self.val=val self.but=Button(borderwidth=1,text=str(self.val),command=lambda parent=self:follow(parent)) self.but.pack() i=moving_but(val=10) root.mainloop()
问题描述
我尝试制作一个能跟随光标中心移动的Tkinter Button,但发现按钮会在光标位置与窗口左上角之间闪烁跳动。若使用event.x-50这类偏移值调整位置,程序可正常运行,但这违背了让按钮跟随光标中心的初衷,请问该如何修复此问题?
问题原因
闪烁的核心是坐标参考系混乱:
- 光标在根窗口上时,
<Motion>事件的event.x/event.y是相对于根窗口的坐标,按钮能被正确放置在光标位置。 - 但按钮移动到光标位置后,光标会落在按钮组件上,后续
<Motion>事件会被按钮捕获,此时event.x/event.y变成了相对于按钮自身的坐标(比如光标在按钮中心时,坐标是按钮宽高的一半)。 - 用这个相对坐标设置按钮在根窗口的
place位置,会导致按钮跳到窗口左上角附近,光标又回到根窗口,坐标再次变回根窗口参考系,按钮又跳回光标位置,如此循环就出现了闪烁。
修复方案
直接获取光标相对于根窗口的全局坐标,避开组件自身的坐标干扰:
- 使用
root.winfo_pointerx()/root.winfo_pointery()获取光标在屏幕上的全局坐标。 - 减去根窗口自身在屏幕上的坐标
root.winfo_rootx()/root.winfo_rooty(),得到光标在根窗口内的准确位置。
修改后的完整代码
from tkinter import * root = Tk() root.geometry('450x500') root.config(bg='#deeffa') def follow(parent): root.bind('<Motion>', lambda event, parent=parent: center_mouser(event, parent)) parent.but.config(command=stop) def stop(): root.unbind('<Motion>') root.config(cursor="arrow") # 停止跟随后恢复光标显示 def center_mouser(event, parent): root.config(cursor="none") # 计算光标在根窗口内的准确坐标 win_x = root.winfo_pointerx() - root.winfo_rootx() win_y = root.winfo_pointery() - root.winfo_rooty() parent.but.place(x=win_x, y=win_y, anchor='center') class moving_but(): def __init__(self, but=None, val=0): self.val = val self.but = Button(borderwidth=1, text=str(self.val), command=lambda parent=self: follow(parent)) self.but.pack() i = moving_but(val=10) root.mainloop()
额外优化
在stop函数中恢复光标显示,避免停止跟随时光标仍处于隐藏状态,提升交互体验。
内容的提问来源于stack exchange,提问作者LOG HAM
相关产品推荐
相关产品推荐

