TkinterDnD2 - Drag and Drop for Tkinter
TkinterDnD2 is a Python wrapper for George Petasis' tkDnD Tk extension version 2, enabling robust drag-and-drop functionality in Tkinter applications. It provides interfaces for registering widgets as drop targets and handling dropped data, including files, text, and custom types. The library is currently at version 0.4.3 and sees sporadic but active maintenance, focusing on cross-platform compatibility and stability for Tkinter projects.
Common errors
-
_tkinter.TclError: couldn't load file "tkdnd2.8.tcl": no such file or directory
cause The underlying `tkDnD` Tk extension, which `tkinterdnd2` wraps, cannot be found by your Tkinter installation. This often happens if Tkinter is not configured correctly or the extension files are missing.fixConsult the `tkinterdnd2` GitHub page or `tkdnd` documentation for instructions on how to ensure the TkDnD extension is properly installed and discoverable by your Tkinter environment. This may involve installing system packages or placing `.tcl` files manually. -
ModuleNotFoundError: No module named 'tkinterdnd2'
cause The `tkinterdnd2` Python package has not been installed in your current Python environment.fixInstall the package using pip: `pip install tkinterdnd2`. -
AttributeError: 'Tk' object has no attribute 'drop_target_register'
cause You are attempting to use drag-and-drop methods like `drop_target_register` on a standard `tkinter.Tk` object instead of an instance that has been augmented by `tkinterdnd2`.fixEnsure your main application window inherits from `tkinterdnd2.TkinterDnD.Tk` (e.g., `class MyApp(TkinterDnD.Tk):`) or explicitly pass your `tk.Tk` instance to `TkinterDnD.TkinterDnD()` to initialize the DND functionality (e.g., `root = tk.Tk(); dnd_manager = TkinterDnD.TkinterDnD(root)`).
Warnings
- gotcha The underlying `tkDnD` Tk extension is required for `tkinterdnd2` to function. If Tkinter is not correctly configured to find it, you might encounter `_tkinter.TclError` messages.
- gotcha When inheriting `TkinterDnD.Tk` or creating a `TkinterDnD.Tk()` instance, it's crucial to call `self.TkinterDnD()` in the `__init__` if not using the inheritance approach (i.e., `root = tk.Tk(); root = TkinterDnD.TkinterDnD(root)`). For best practice, inherit `TkinterDnD.Tk` directly.
- breaking Prior to version 0.4.3, `tkinterdnd2` had less robust platform detection, potentially leading to issues on non-Windows systems, especially regarding file path parsing or DND initialization.
Install
-
pip install tkinterdnd2
Imports
- TkinterDnD
import tkinterdnd2; app = tkinterdnd2.TkinterDnD()
from tkinterdnd2 import TkinterDnD
- DND_FILES
from tkinterdnd2 import DND_FILES
Quickstart
import tkinter as tk
from tkinterdnd2 import DND_FILES, TkinterDnD
class MyDNDApp(TkinterDnD.Tk):
def __init__(self):
super().__init__()
self.title("TkinterDnD2 Drop Example")
self.geometry("400x300")
self.dnd_label = tk.Label(
self,
text="Drag & drop files here!",
width=40, height=10,
relief="groove",
bg="lightgray"
)
self.dnd_label.pack(padx=20, pady=20)
# Register the label as a drop target for files
self.dnd_label.drop_target_register(DND_FILES)
# Bind the drop event to a handler function
self.dnd_label.dnd_bind('<<Drop>>', self.handle_drop)
def handle_drop(self, event):
# event.data contains the dropped data (e.g., file paths)
# It's a space-separated string if multiple files are dropped
dropped_items = event.data.strip().split(' ') # Basic parsing
self.dnd_label.config(text=f"Dropped: {dropped_items[0]}\n({len(dropped_items)} items)")
print(f"Dropped items: {dropped_items}")
if __name__ == "__main__":
app = MyDNDApp()
app.mainloop()