├── LICENSE ├── README.md └── tkinterDnD.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 TechDudie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tkinterDnD 2 | Tkinter Drag-N-Drop module. 3 | 4 | Import this module with 5 | 6 | ```python 7 | import tkinterDnD as dnd 8 | ``` 9 | 10 | To make a widget draggable, do 11 | 12 | ```python 13 | dnd.make_draggable(widget) 14 | ``` 15 | 16 | To make a draggable widget inside a frame, do 17 | 18 | ```python 19 | dnd.make_draggable(frame) 20 | dnd.make_draggable_component(widget) 21 | ``` 22 | 23 | Here's an example of this module being put to use. 24 | 25 | ```python 26 | import tkinter 27 | import tkinterDnD as dnd 28 | tk = tkinter.Tk() 29 | tk.title("tkinterDnD") 30 | frame = tkinter.Frame(tk, bd=4, height=64, width=64, bg="red") 31 | frame.place(x=0,y=0) 32 | dnd.make_draggable(frame) 33 | label = tkinter.Label(frame, text="Hello", bg="red", wraplength=64, justify=tkinter.CENTER) 34 | label.config(highlightbackground="black") 35 | label.place(relx=0.5, rely=0.5, anchor=tkinter.CENTER) 36 | dnd.make_draggable_component(label) 37 | frame = tkinter.Frame(tk, bd=4, height=64, width=64, bg="green") 38 | frame.place(x=0,y=0) 39 | dnd.make_draggable(frame) 40 | label = tkinter.Label(frame, text="World", bg="green", wraplength=64, justify=tkinter.CENTER) 41 | label.config(highlightbackground="black") 42 | label.place(relx=0.5, rely=0.5, anchor=tkinter.CENTER) 43 | dnd.make_draggable_component(label) 44 | tk.mainloop() 45 | ``` 46 | 47 | # Side note: The module has a default snap grid of 16x16 units. 48 | 49 | Set the snap grid with dnd.set_grid(grid) 50 | -------------------------------------------------------------------------------- /tkinterDnD.py: -------------------------------------------------------------------------------- 1 | global grid 2 | grid = 16 3 | def make_draggable(widget): 4 | widget.bind("", on_drag_start) 5 | widget.bind("", on_drag_motion) 6 | widget.bind("", on_drag_release) 7 | def make_draggable_component(widget): 8 | widget.bind("", on_component_drag_start) 9 | widget.bind("", on_component_drag_motion) 10 | widget.bind("", on_component_drag_release) 11 | def on_drag_start(event): 12 | widget = event.widget 13 | widget._drag_start_x = event.x 14 | widget._drag_start_y = event.y 15 | def on_drag_motion(event): 16 | widget = event.widget 17 | x = widget.winfo_x() - widget._drag_start_x + event.x 18 | y = widget.winfo_y() - widget._drag_start_y + event.y 19 | widget.place(x=x, y=y) 20 | def on_drag_release(event): 21 | global grid 22 | widget = event.widget 23 | x = round((widget.winfo_x() - widget._drag_start_x + event.x) / grid) * grid 24 | y = round((widget.winfo_y() - widget._drag_start_y + event.y) / grid) * grid 25 | widget.place(x=x, y=y) 26 | def on_component_drag_start(event): 27 | widget = event.widget 28 | container = widget.nametowidget(widget.winfo_parent()) 29 | container._drag_start_x = event.x 30 | container._drag_start_y = event.y 31 | def on_component_drag_motion(event): 32 | widget = event.widget 33 | container = widget.nametowidget(widget.winfo_parent()) 34 | x = container.winfo_x() - container._drag_start_x + event.x 35 | y = container.winfo_y() - container._drag_start_y + event.y 36 | container.place(x=x, y=y) 37 | def on_component_drag_release(event): 38 | global grid 39 | widget = event.widget 40 | container = widget.nametowidget(widget.winfo_parent()) 41 | x = round((container.winfo_x() - container._drag_start_x + event.x) / grid) * grid 42 | y = round((container.winfo_y() - container._drag_start_y + event.y) / grid) * grid 43 | container.place(x=x, y=y) 44 | def set_grid(measure): 45 | global grid 46 | grid = measure 47 | --------------------------------------------------------------------------------