Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources]

David Ascher, Alex Martelli, Anna Ravenscroft

نسخه متنی -صفحه : 394/ 230
نمايش فراداده

Recipe 11.4. Adding Drag and Drop Reordering to a Tkinter Listbox

Credit: John Fouhy

Problem

You want to use a Tkinter Listbox widget, but you want to give the user the additional capability of reordering the entries by drag-and-drop.

Solution

We just need to code the relevant functionality and bind it to the Tkinter event corresponding to the "drag" mouse gesture:

import Tkinter
class DDList(Tkinter.Listbox):
"" A Tkinter listbox with drag'n'drop reordering of entries. ""
def _ _init_ _(self, master, **kw):
kw['selectmode'] = Tkinter.SINGLE
Tkinter.Listbox._ _init_ _(self, master, kw)
self.bind('<Button-1>', self.setCurrent)
self.bind('<B1-Motion>', self.shiftSelection)
self.curIndex = None
def setCurrent(self, event):
self.curIndex = self.nearest(event.y)
def shiftSelection(self, event):
i = self.nearest(event.y)
if i < self.curIndex:
x = self.get(i)
self.delete(i)
self.insert(i+1, x)
self.curIndex = i
elif i > self.curIndex:
x = self.get(i)
self.delete(i)
self.insert(i-1, x)
self.curIndex = i

Discussion

Here is an example of use of this DDList class, presented, as usual, with a guard of if _ _name_ _ == '_ _main_ _' so we can make it part of the module containing the class and have it run when the module is executed as a "main script":

if _ _name_ _ == '_ _main_ _':
tk = Tkinter.Tk( )
length = 10
dd = DDList(tk, height=length)
dd.pack( )
for i in xrange(length):
dd.insert(Tkinter.END, str(i))
def show( ):
''' show the current ordering every 2 seconds '''
for x in dd.get(0, Tkinter.END):
print x,
print
tk.after(2000, show)
tk.after(2000, show)
tk.mainloop( )

Allowing the user of a GUI program to drag the elements of a list into new positions is often useful, and this recipe shows a fairly simple way of adding this functionality to a Tkinter Listbox widget.

This recipe's code tries to ensure that the clicked-on element stays selected by deleting and inserting on either side of it. Nevertheless, it is possible, by moving the mouse quickly enough, to start dragging an unselected element instead. While it doesn't cause any major problems, it just looks a bit odd.

This recipe's code is partly based on a post by Fredrik Lundh, http://mail.python.org/pipermail/python-list/1999-May/002501l.

See Also

Information about Tkinter can be obtained from a variety of sources, such as Fredrik Lundh, An Introduction to Tkinter (PythonWare: http://www.pythonware.com/library), New Mexico Tech's Tkinter Reference (http://www.nmt.edu/tcc/help/lang/python/docsl), Python in a Nutshell, and various other books.