Ralf Schmitt wrote: Hi, As I haven't found an example of using drag'n drop between multiple `wxTreeCtrl's`, I'm posting a short example program, just in case that someone else will have the same problem... It also allows dnd between two programs, and dragging of files onto `wxTreeCtrl's`. - Ralf {{{ #!python # Drag and Drop contributed by Sam Anderson, reposted by Dirk Krause import cPickle as pickle from xml.parsers import expat import wx # Use the new namespace class DropData(wx.CustomDataObject): def __init__(self): wx.CustomDataObject.__init__(self, wx.CustomDataFormat("MyDropData")) self.setObject(None) def setObject(self, obj): self.SetData(pickle.dumps(obj)) def getObject(self): return pickle.loads(self.GetData()) class MyDropTarget(wx.PyDropTarget): def __init__(self, tree): wx.PyDropTarget.__init__(self) self._makeObjects() self.tree = tree self.selections=[] def _makeObjects(self): self.data = DropData() self.fileObject = wx.FileDataObject() comp = wx.DataObjectComposite() comp.Add(self.data) comp.Add(self.fileObject) self.comp = comp self.SetDataObject(comp) def _saveSelection(self): self.selections = self.tree.GetSelections() self.tree.UnselectAll() def _restoreSelection(self): self.tree.UnselectAll() for i in self.selections: self.tree.SelectItem(i) self.selections=[] def OnEnter(self, x, y, d): self._saveSelection() return d def OnLeave(self): self._restoreSelection() def OnDrop(self, x, y): self._restoreSelection() #item, flags = self.tree.HitTest((x, y)) print "got an drop event at", x, y return True def OnDragOver(self, x, y, d): # provide visual feedback by selecting the item the mouse is over item, flags = self.tree.HitTest((x,y)) selections = self.tree.GetSelections() if item: if selections != [item]: self.tree.UnselectAll() self.tree.SelectItem(item) elif selections: self.tree.UnselectAll() # The value returned here tells the source what kind of visual # feedback to give. For example, if wx.DragCopy is returned then # only the copy cursor will be shown, even if the source allows # moves. You can use the passed in (x,y) to determine what kind # of feedback to give. In this case we return the suggested value # which is based on whether the Ctrl key is pressed. return d # Called when OnDrop returns True. We need to get the data and # do something with it. def OnData(self, x, y, d): if self.GetData(): filenames = self.fileObject.GetFilenames() data = self.data.getObject() print "====>", if filenames: print "files", filenames, if data: print "item", repr(data), item, flags = self.tree.HitTest((x,y)) if item: print "dropped on item:", self.tree.GetItemText(item) else: print "dropped nowhere" self._makeObjects() # reset data objects.. return d # what is returned signals the source what to do # with the original data (move, copy, etc.) In this # case we just return the suggested value given to us. # dummy xml file xml=''' ''' class TestApp(wx.App): def OnInit(self): # create navigation frame frame = NavFrame(None, -1, 'wx.TreeCtrl DragNDrop Test') for tree in frame.trees: # expand a few nodes # NOTE: I know this is pathetic but I couldn't figure out how # to walk through and expand all nodes root = tree.nodeStack[0] child, cookie = tree.GetFirstChild(root) nchild, cookie = tree.GetFirstChild(child) tree.Expand(root) tree.Expand(child) tree.Expand(nchild) # display navigation frame frame.Show(True) self.SetTopWindow(frame) return True class NavFrame(wx.Frame): def __init__(self, parent, ID, title): wx.Frame.__init__(self, parent, ID, title, wx.DefaultPosition, wx.Size(650,400)) self.ils = [] self.trees = [] self.newTree((20,20)) self.newTree((300,20)) # other events self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) def newTree(self, pos): # give the tree a unique id tID = wx.NewId() # call the tree tree = XMLTree(self, tID, pos, wx.Size(270,290), # wx.DefaultPosition, wx.Size(270,490), wx.TR_HAS_BUTTONS | wx.TR_MULTIPLE)# | wx.TR_EDIT_LABELS) # Trees need an image list to do DnD... tree.SetImageList(self.MakeImageList()) # Load XML into tree tree.LoadXML() md=MyDropTarget(tree) tree.SetDropTarget(md) tree.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnBeginDrag) self.trees.append(tree) def OnBeginDrag(self, event): item = event.GetItem() tree = event.GetEventObject() if item != tree.GetRootItem(): # prevent dragging root item def DoDragDrop(): txt = tree.GetItemText(item) print "Starting drag'n'drop with %s..." % repr(txt) dd = DropData() dd.setObject(txt) comp = wx.DataObjectComposite() comp.Add(dd) dropSource = wx.DropSource(self) dropSource.SetData(comp) result = dropSource.DoDragDrop(wx.Drag_AllowMove) print "drag'n'drop finished with:", result, "\n" wx.CallAfter(DoDragDrop) # can't call dropSource.DoDragDrop here.. def OnCloseWindow(self, event): self.Destroy() def MakeImageList(self): il = wx.ImageList(16, 16) il.Add(wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, (16, 16))) self.ils.append(il) return il class XMLTree(wx.TreeCtrl): def __init__(self, parent, id, pos, size, style): wx.TreeCtrl.__init__(self, parent, id, pos, size, style) # create nodeStack and add root node self.nodeStack = [self.AddRoot("My InfoSpace")] def StartElement(self, name, attrs ): name = name.encode() id = self.AppendItem(self.nodeStack[-1], name) # for each element map xml attributes to an associated dictionary self.SetPyData(id, attrs) # set title of tree node based on element title attribute if 'title' in attrs: title = attrs['title'] self.SetItemText(id, str(title)) # add element to tree self.nodeStack.append(id) def EndElement(self, name ): self.nodeStack = self.nodeStack[:-1] def CharacterData(self, data ): if data.strip(): data = "" self.AppendItem(self.nodeStack[-1], data) def LoadXML(self): Parser = expat.ParserCreate() Parser.StartElementHandler = self.StartElement Parser.EndElementHandler = self.EndElement Parser.CharacterDataHandler = self.CharacterData ParserStatus = Parser.Parse(xml, 1) if __name__ == '__main__': app = TestApp(False) app.MainLoop() }}}