Recipe 11.4. Adding Drag and Drop Reordering to a Tkinter ListboxCredit: John Fouhy ProblemYou 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. SolutionWe 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 DiscussionHere 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/002501.html. See AlsoInformation 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/docs.html), Python in a Nutshell, and various other books. |