您所观察到的行为是由于事件的坐标是相对于拖动小部件而言的。使用相对坐标更新小部件在绝对坐标中的位置显然会导致混乱。
为了解决这个问题,我使用了
.winfo_x()
和.winfo_y()
函数(它们允许将相对坐标转换为绝对坐标),以及
Button-1
事件来确定拖动开始时光标在小部件上的位置。
下面是一个使小部件可拖动的函数:
def make_draggable(widget):
widget.bind("<Button-1>", on_drag_start)
widget.bind("<B1-Motion>", on_drag_motion)
def on_drag_start(event):
widget = event.widget
widget._drag_start_x = event.x
widget._drag_start_y = event.y
def on_drag_motion(event):
widget = event.widget
x = widget.winfo_x() - widget._drag_start_x + event.x
y = widget.winfo_y() - widget._drag_start_y + event.y
widget.place(x=x, y=y)
它可以这样使用:
main = tk.Tk()
frame = tk.Frame(main, bd=4, bg="grey")
frame.place(x=10, y=10)
make_draggable(frame)
notes = tk.Text(frame)
notes.pack()
如果您想采用更面向对象的方法,可以编写一个
mixin,使类的所有实例都可拖动:
class DragDropMixin:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
make_draggable(self)
使用方法:
class DnDFrame(DragDropMixin, tk.Frame):
pass
main = tk.Tk()
frame = DnDFrame(main, bd=4, bg="grey")
frame.place(x=10, y=10)
notes = tk.Text(frame)
notes.pack()