Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drag and drop explorer files to tkinter entry widget?

Tags:

python

tkinter

I'm fairly new to Python. I'm trying to input a file name (complete with full path) to a TKinter entry widget. Since the path to the file name can be very long I would like to be able to drag and drop the file directly from Windows Explorer. In Perl I have seen the following:

use Tk::DropSite; . . my $mw = new MainWindow; $top = $mw->Toplevel; $label_entry = $top->Entry(-width => '45',. -background => 'ivory2')->pack(); $label_entry->DropSite(-dropcommand => \&drop,-droptypes => 'Win32',); 

Is there something similar I can do using TKinter in Python?

like image 406
George Joseph Avatar asked Jan 10 '13 21:01

George Joseph


People also ask

Can you drag and drop in tkinter?

The tkinter. dnd module provides drag-and-drop support for objects within a single application, within the same window or between windows. To enable an object to be dragged, you must create an event binding for it that starts the drag-and-drop process.

How do you add drag and drop in Python?

However, the simplest way to enable dragging from a widget is to reimplement the widget's mousePressEvent() and start a drag and drop operation: def mousePressEvent(self, event): if (event. button() == Qt. LeftButton and iconLabel.

Which widget we use for entry data in tkinter?

The Entry widget is used to accept single-line text strings from a user. If you want to display multiple lines of text that can be edited, then you should use the Text widget. If you want to display one or more lines of text that cannot be modified by the user, then you should use the Label widget.


2 Answers

Tk does not have any command to handle that, and Python doesn't include any extra Tk extension to perform drag & drop inter-applications, therefore you need an extension to perform the operation. Tkdnd (the Tk extension at http://sourceforge.net/projects/tkdnd, not the Tkdnd.py module) works for me. To use it from Python, a wrapper is required. Quickly searching for one, it seems http://mail.python.org/pipermail/tkinter-discuss/2005-July/000476.html contains such code. I did another one because I didn't like that other one. The problem with my wrapper is that it is highly untested, in fact I only used the function bindtarget and only for 10 seconds or so.

With the wrapper below, you can create some widget and announce that it supports receiving dragged files. Here is one example:

# The next two lines are not necessary if you installed TkDnd # in a proper place. import os os.environ['TKDND_LIBRARY'] = DIRECTORYTOTHETKDNDBINARY  import Tkinter from untested_tkdnd_wrapper import TkDND  root = Tkinter.Tk()  dnd = TkDND(root)  entry = Tkinter.Entry() entry.pack()  def handle(event):     event.widget.insert(0, event.data)  dnd.bindtarget(entry, handle, 'text/uri-list')  root.mainloop() 

And here is the code for untested_tkdnd_wrapper.py:

import os import Tkinter  def _load_tkdnd(master):     tkdndlib = os.environ.get('TKDND_LIBRARY')     if tkdndlib:         master.tk.eval('global auto_path; lappend auto_path {%s}' % tkdndlib)     master.tk.eval('package require tkdnd')     master._tkdnd_loaded = True   class TkDND(object):     def __init__(self, master):         if not getattr(master, '_tkdnd_loaded', False):             _load_tkdnd(master)         self.master = master         self.tk = master.tk      # Available pre-defined values for the 'dndtype' parameter:     #   text/plain     #   text/plain;charset=UTF-8     #   text/uri-list      def bindtarget(self, window, callback, dndtype, event='<Drop>', priority=50):         cmd = self._prepare_tkdnd_func(callback)         return self.tk.call('dnd', 'bindtarget', window, dndtype, event,                 cmd, priority)      def bindtarget_query(self, window, dndtype=None, event='<Drop>'):         return self.tk.call('dnd', 'bindtarget', window, dndtype, event)      def cleartarget(self, window):         self.tk.call('dnd', 'cleartarget', window)       def bindsource(self, window, callback, dndtype, priority=50):         cmd = self._prepare_tkdnd_func(callback)         self.tk.call('dnd', 'bindsource', window, dndtype, cmd, priority)      def bindsource_query(self, window, dndtype=None):         return self.tk.call('dnd', 'bindsource', window, dndtype)      def clearsource(self, window):         self.tk.call('dnd', 'clearsource', window)       def drag(self, window, actions=None, descriptions=None,             cursorwin=None, callback=None):         cmd = None         if cursorwin is not None:             if callback is not None:                 cmd = self._prepare_tkdnd_func(callback)         self.tk.call('dnd', 'drag', window, actions, descriptions,                 cursorwin, cmd)       _subst_format = ('%A', '%a', '%b', '%D', '%d', '%m', '%T',             '%W', '%X', '%Y', '%x', '%y')     _subst_format_str = " ".join(_subst_format)      def _prepare_tkdnd_func(self, callback):         funcid = self.master.register(callback, self._dndsubstitute)         cmd = ('%s %s' % (funcid, self._subst_format_str))         return cmd      def _dndsubstitute(self, *args):         if len(args) != len(self._subst_format):             return args          def try_int(x):             x = str(x)             try:                 return int(x)             except ValueError:                 return x          A, a, b, D, d, m, T, W, X, Y, x, y = args          event = Tkinter.Event()         event.action = A       # Current action of the drag and drop operation.         event.action_list = a  # Action list supported by the drag source.         event.mouse_button = b # Mouse button pressed during the drag and drop.         event.data = D         # The data that has been dropped.         event.descr = d        # The list of descriptions.         event.modifier = m     # The list of modifier keyboard keys pressed.         event.dndtype = T         event.widget = self.master.nametowidget(W)         event.x_root = X       # Mouse pointer x coord, relative to the root win.         event.y_root = Y         event.x = x            # Mouse pointer x coord, relative to the widget.         event.y = y          event.action_list = str(event.action_list).split()         for name in ('mouse_button', 'x', 'y', 'x_root', 'y_root'):             setattr(event, name, try_int(getattr(event, name)))          return (event, ) 

Together with Tkdnd, you will find a tkdnd.tcl program which is a higher level over the own C extension it provides. I didn't wrap this higher level code, but it could be more interesting to replicate it in Python than to use this lower level wrapper.

like image 150
mmgp Avatar answered Sep 28 '22 07:09

mmgp


Things have progressed since this question was originally posted, and tkdnd2.8 (Tcl extensions) and TkinterDnD2 (Python wrapper for tkdnd2.8) are readily available on SourceForge.net.

Here's minimal sample code to do exactly what you've asked.

import Tkinter from TkinterDnD2 import *  def drop(event):     entry_sv.set(event.data)  root = TkinterDnD.Tk() entry_sv = Tkinter.StringVar() entry = Tkinter.Entry(root, textvar=entry_sv, width=80) entry.pack(fill=Tkinter.X) entry.drop_target_register(DND_FILES) entry.dnd_bind('<<Drop>>', drop) root.mainloop() 

You can see How to Install and Use TkDnD with Python 2.7 Tkinter on OSX for download and installation info for both Windows and Mac on Python 2.7 and 3.6.

like image 34
Gary02127 Avatar answered Sep 28 '22 06:09

Gary02127