Ralf Schmitt wrote:

   1 # Drag and Drop contributed by Sam Anderson, reposted by Dirk Krause
   2 
   3 import cPickle as pickle
   4 from xml.parsers import expat
   5 
   6 import wx # Use the new namespace
   7 
   8 
   9 class DropData(wx.CustomDataObject):
  10     def __init__(self):
  11         wx.CustomDataObject.__init__(self, wx.CustomDataFormat("MyDropData"))
  12         self.setObject(None)
  13 
  14     def setObject(self, obj):
  15         self.SetData(pickle.dumps(obj))
  16 
  17     def getObject(self):
  18         return pickle.loads(self.GetData())
  19 
  20 
  21 class MyDropTarget(wx.PyDropTarget):
  22     def __init__(self, tree):
  23         wx.PyDropTarget.__init__(self)
  24         self._makeObjects()
  25         self.tree = tree
  26         self.selections=[]
  27 
  28     def _makeObjects(self):
  29         self.data = DropData()
  30         self.fileObject = wx.FileDataObject()
  31         comp = wx.DataObjectComposite()
  32         comp.Add(self.data)
  33         comp.Add(self.fileObject)
  34         self.comp = comp
  35         self.SetDataObject(comp)
  36 
  37     def _saveSelection(self):
  38         self.selections = self.tree.GetSelections()
  39         self.tree.UnselectAll()
  40 
  41     def _restoreSelection(self):
  42         self.tree.UnselectAll()
  43         for i in self.selections:
  44             self.tree.SelectItem(i)
  45         self.selections=[]
  46 
  47 
  48     def OnEnter(self, x, y, d):
  49         self._saveSelection()
  50         return d
  51 
  52     def OnLeave(self):
  53         self._restoreSelection()
  54 
  55     def OnDrop(self, x, y):
  56         self._restoreSelection()
  57         #item, flags = self.tree.HitTest((x, y))
  58         print "got an drop event at", x, y
  59         return True
  60 
  61     def OnDragOver(self, x, y, d):
  62         # provide visual feedback by selecting the item the mouse is over
  63         item, flags = self.tree.HitTest((x,y))
  64         selections = self.tree.GetSelections()
  65         if item:
  66             if selections != [item]:
  67                 self.tree.UnselectAll()
  68                 self.tree.SelectItem(item)
  69         elif selections:
  70             self.tree.UnselectAll()
  71 
  72         # The value returned here tells the source what kind of visual
  73         # feedback to give.  For example, if wx.DragCopy is returned then
  74         # only the copy cursor will be shown, even if the source allows
  75         # moves.  You can use the passed in (x,y) to determine what kind
  76         # of feedback to give.  In this case we return the suggested value
  77         # which is based on whether the Ctrl key is pressed.
  78         return d
  79 
  80 
  81 
  82     # Called when OnDrop returns True.  We need to get the data and
  83     # do something with it.
  84     def OnData(self, x, y, d):
  85         if self.GetData():
  86             filenames = self.fileObject.GetFilenames()
  87             data = self.data.getObject()
  88 
  89             print "====>",
  90             if filenames:
  91                 print "files", filenames,
  92 
  93             if data:
  94                 print "item", repr(data),
  95 
  96             item, flags = self.tree.HitTest((x,y))
  97             if item:
  98                 print "dropped on item:", self.tree.GetItemText(item)
  99             else:
 100                 print "dropped nowhere"
 101 
 102             self._makeObjects()   # reset data objects..
 103 
 104         return d  # what is returned signals the source what to do
 105                   # with the original data (move, copy, etc.)  In this
 106                   # case we just return the suggested value given to us.
 107 
 108 
 109 # dummy xml file
 110 xml='''<?xml version="1.0" encoding="UTF-8"?>
 111 <Test title="Channels">
 112  <Channels title="Favourites">
 113   <Channel type="channel" title="Slashdot" uri="http://slashdot.org"/>
 114  </Channels>
 115  <Channels title="News">
 116   <Channel title="CNN" uri="http://cnn.com"/>
 117   <Channel title="BBC" uri="http://bbc.co.uk"/>
 118   <Channel title="The Economist" uri="http://economist.com"/>
 119   <Channel title="MSNB" uri="http://msnbc.com"/>
 120  </Channels>
 121  <Channels title="Sports">
 122   <Channel type="channel" title="ESPN" uri="http://espn.com"/>
 123  </Channels>
 124  <Trash title="Trash"/>
 125 </Test>'''
 126 
 127 class TestApp(wx.App):
 128     def OnInit(self):
 129         # create navigation frame
 130         frame = NavFrame(None, -1, 'wx.TreeCtrl DragNDrop Test')
 131         for tree in frame.trees:
 132             # expand a few nodes
 133             # NOTE: I know this is pathetic but I couldn't figure out how
 134             # to walk through and expand all nodes
 135             root = tree.nodeStack[0]
 136             child, cookie = tree.GetFirstChild(root)
 137             nchild, cookie = tree.GetFirstChild(child)
 138             tree.Expand(root)
 139             tree.Expand(child)
 140             tree.Expand(nchild)
 141 
 142         # display navigation frame
 143         frame.Show(True)
 144         self.SetTopWindow(frame)
 145         return True
 146 
 147 class NavFrame(wx.Frame):
 148     def __init__(self, parent, ID, title):
 149         wx.Frame.__init__(self, parent, ID, title,
 150            wx.DefaultPosition,
 151            wx.Size(650,400))
 152         self.ils = []
 153         self.trees = []
 154         self.newTree((20,20))
 155         self.newTree((300,20))
 156         # other events
 157         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 158 
 159     def newTree(self, pos):
 160         # give the tree a unique id
 161         tID = wx.NewId()
 162 
 163         # call the tree
 164         tree = XMLTree(self, tID, pos, wx.Size(270,290), # wx.DefaultPosition, wx.Size(270,490),
 165              wx.TR_HAS_BUTTONS | wx.TR_MULTIPLE)# | wx.TR_EDIT_LABELS)
 166         # Trees need an image list to do DnD...
 167         tree.SetImageList(self.MakeImageList())
 168 
 169         # Load XML into tree
 170         tree.LoadXML()
 171 
 172 
 173         md=MyDropTarget(tree)
 174         tree.SetDropTarget(md)
 175 
 176         tree.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnBeginDrag)
 177         self.trees.append(tree)
 178 
 179     def OnBeginDrag(self, event):
 180         item = event.GetItem()
 181         tree = event.GetEventObject()
 182 
 183         if item != tree.GetRootItem(): # prevent dragging root item
 184             def DoDragDrop():
 185                 txt = tree.GetItemText(item)
 186                 print "Starting drag'n'drop with %s..." % repr(txt)
 187                 dd = DropData()
 188                 dd.setObject(txt)
 189 
 190                 comp = wx.DataObjectComposite()
 191                 comp.Add(dd)
 192                 dropSource = wx.DropSource(self)
 193                 dropSource.SetData(comp)
 194                 result = dropSource.DoDragDrop(wx.Drag_AllowMove)
 195                 print "drag'n'drop finished with:", result, "\n"
 196 
 197             wx.CallAfter(DoDragDrop) # can't call dropSource.DoDragDrop here..
 198 
 199 
 200     def OnCloseWindow(self, event):
 201         self.Destroy()
 202 
 203     def MakeImageList(self):
 204         il = wx.ImageList(16, 16)
 205         il.Add(wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, (16, 16)))
 206         self.ils.append(il)
 207         return il
 208 
 209 class XMLTree(wx.TreeCtrl):
 210     def __init__(self, parent, id, pos, size, style):
 211         wx.TreeCtrl.__init__(self, parent, id, pos, size, style)
 212 
 213         # create nodeStack and add root node
 214         self.nodeStack = [self.AddRoot("My InfoSpace")]
 215 
 216     def StartElement(self, name, attrs ):
 217         name = name.encode()
 218 
 219         id = self.AppendItem(self.nodeStack[-1], name)
 220 
 221         # for each element map xml attributes to an associated dictionary
 222         self.SetPyData(id, attrs)
 223 
 224         # set title of tree node based on element title attribute
 225         if 'title' in attrs:
 226             title = attrs['title']
 227             self.SetItemText(id, str(title))
 228 
 229         # add element to tree
 230         self.nodeStack.append(id)
 231 
 232     def EndElement(self,  name ):
 233         self.nodeStack = self.nodeStack[:-1]
 234 
 235     def CharacterData(self, data ):
 236         if data.strip():
 237             data = ""
 238             self.AppendItem(self.nodeStack[-1], data)
 239 
 240     def LoadXML(self):
 241         Parser = expat.ParserCreate()
 242 
 243         Parser.StartElementHandler = self.StartElement
 244         Parser.EndElementHandler = self.EndElement
 245         Parser.CharacterDataHandler = self.CharacterData
 246 
 247         ParserStatus = Parser.Parse(xml, 1)
 248 
 249 
 250 if __name__ == '__main__':
 251     app = TestApp(False)
 252     app.MainLoop()

TreeCtrlDnD (last edited 2010-01-17 07:13:40 by s235-200)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.