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
···
========================
#! /usr/bin/env python
# Drag and Drop contributed by Sam Anderson, reposted by Dirk Krause
import string
import cPickle as pickle
from xml.parsers import expat
from wxPython.wx import *
wxInitAllImageHandlers()
class DropData(wxCustomDataObject):
def __init__(self):
wxCustomDataObject.__init__(self, wxCustomDataFormat("MyDropData"))
self.setObject(None)
def setObject(self, obj):
self.SetData(pickle.dumps(obj))
def getObject(self):
return pickle.loads(self.GetData())
class MyDropTarget(wxPyDropTarget):
def __init__(self, tree):
wxPyDropTarget.__init__(self)
self._makeObjects()
self.tree = tree
self.selections=[]
def _makeObjects(self):
self.data = DropData()
self.fileObject = wxFileDataObject()
comp = wxDataObjectComposite()
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 wxDragCopy 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='''<?xml version="1.0" encoding="UTF-8"?>
<Test title="Channels">
<Channels title="Favourites">
<Channel type="channel" title="Slashdot" uri="http://slashdot.org"/>
</Channels>
<Channels title="News">
<Channel title="CNN" uri="http://cnn.com"/>
<Channel title="BBC" uri="http://bbc.co.uk"/>
<Channel title="The Economist" uri="http://economist.com"/>
<Channel title="MSNB" uri="http://msnbc.com"/>
</Channels>
<Channels title="Sports">
<Channel type="channel" title="ESPN" uri="http://espn.com"/>
</Channels>
<Trash title="Trash"/>
</Test>'''
class TestApp(wxApp):
def OnInit(self):
# create navigation frame
frame = NavFrame(NULL, -1, 'wxTreeCtrl 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, 0)
nchild, cookie = tree.GetFirstChild(child, 0)
tree.Expand(root)
tree.Expand(child)
tree.Expand(nchild)
# display navigation frame
frame.Show(true)
self.SetTopWindow(frame)
return true
class NavFrame(wxFrame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title,
wxDefaultPosition,
wxSize(650,400))
self.ils = []
self.trees = []
self.newTree((20,20))
self.newTree((300,20))
# other events
EVT_CLOSE(self, self.OnCloseWindow)
def newTree(self, pos):
# give the tree a unique id
tID = wxNewId()
# call the tree
tree = XMLTree(self, tID, pos, wxSize(270,290), # wxDefaultPosition, wxSize(270,490),
wxTR_HAS_BUTTONS | wxTR_MULTIPLE)# | wxTR_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)
EVT_TREE_BEGIN_DRAG(tree, tID, 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 = wxDataObjectComposite()
comp.Add(dd)
dropSource = wxDropSource(self)
dropSource.SetData(comp)
result = dropSource.DoDragDrop(wxDrag_AllowMove)
print "drag'n'drop finished with:", result, "\n"
wxCallAfter(DoDragDrop) # can't call dropSource.DoDragDrop here..
def OnCloseWindow(self, event):
self.Destroy()
def MakeImageList(self):
il = wxImageList(16, 16)
bmp = wxBitmap("FolderNormal.gif", wxBITMAP_TYPE_GIF)
il.Add(bmp)
self.ils.append(il)
return il
class XMLTree(wxTreeCtrl):
def __init__(self, parent, id, pos, size, style):
wxTreeCtrl.__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 attrs.has_key('title'):
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 string.strip(data):
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(0)
app.MainLoop()
--
brainbot technologies ag
boppstrasse 64 . 55118 mainz . germany
fon +49 6131 211639-1 . fax +49 6131 211639-2
http://brainbot.com/ mailto:ralf@brainbot.com