Drag and Drop widgets tkinter

Drag and Drop widgets tkinter



I am trying to make a Python program in which you can move around widgets.



This is my code:


import tkinter as tk
main = tk.Tk()
notesFrame = tk.Frame(main, bd = 4, bg = "a6a6a6")
notesFrame.place(x=10,y=10)
notes = tk.Text(notesFrame)
notes.pack()
notesFrame.bind("<B1-Motion>", lambda event: notesFrame.place(x = event.x, y = event.y)



But, this gets super glitchy and the widget jumps back and forth.



Thanks!






Did you actually try this code? Cause it has multiple errors, and doesn't appear to move anything - at least under Python 3.5 on Mac.

– Wayne Werner
May 17 '16 at 15:18







You have the click the border, not the text box

– MrYurihi redstone
May 17 '16 at 15:39





2 Answers
2



The behavior you're observing is caused by the fact that the event's coordinates are relative to the dragged widget. Updating the widget's position (in absolute coordinates) with relative coordinates obviously results in chaos.



To fix this, I've used the .winfo_x() and .winfo_y() functions (which allow to turn the relative coordinates into absolute ones), and the Button-1 event to determine the cursor's location on the widget when the drag starts.
The following is a mixin that makes a widget draggable.


.winfo_x()


.winfo_y()


Button-1


class DragDropMixin:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

self.drag_start_x = 0
self.drag_start_y = 0
self.bind("<Button-1>", self.drag_start)
self.bind("<B1-Motion>", self.drag_motion)

def drag_start(self, event):
self.drag_start_x = event.x
self.drag_start_y = event.y

def drag_motion(self, event):
x = self.winfo_x() - self.drag_start_x + event.x
y = self.winfo_y() - self.drag_start_y + event.y
self.place(x=x, y=y)



Usage:


# As always when it comes to mixins, make sure to
# inherit from DragDropMixin FIRST!
class DnDFrame(DragDropMixin, tk.Frame):
pass

# This wouldn't work:
# class DnDFrame(tk.Frame, DragDropMixin):
# pass

main = tk.Tk()
frame = DnDFrame(main, bd=4, bg="grey")
frame.place(x=10, y=10)
notes = tk.Text(frame)
notes.pack()






Thanks! It worked

– MrYurihi redstone
May 17 '16 at 21:06



Tkinter has a module for this, documented in the module docstring. It was expected that it would be replaced by a tk dnd module, but this has not happened. I have never tried it. Searching SO for [tkinter] dnd returns this page. Below is the beginning of the docstring.


[tkinter] dnd


>>> from tkinter import dnd
>>> help(dnd)
Help on module tkinter.dnd in tkinter:

NAME
tkinter.dnd - Drag-and-drop support for Tkinter.

DESCRIPTION
This is very preliminary. I currently only support dnd *within* one
application, between different windows (or within the same window).
[snip]



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)