204 lines
7.3 KiB
Python
204 lines
7.3 KiB
Python
|
"""
|
||
|
Hello, and welcome to this test of the wxTreeItemData class.
|
||
|
|
||
|
The wxTreeItemData class can be used to associate a python object with
|
||
|
a wxTreeCtrl item. In this sample, its use is demonstrated via a tree
|
||
|
control that shows the contents of a python namespace according to the
|
||
|
standard dir() command. Every item in the tree has its label taken
|
||
|
from the dir() output, and 'behind it' a reference to the python
|
||
|
object is stored in a wxTreeItemData object.
|
||
|
|
||
|
As you may have guessed by now, this sample automatically displays
|
||
|
'__doc__' strings if the selected python object happens to have
|
||
|
one. Please expand the pyTree object to learn more about the
|
||
|
implementation.
|
||
|
|
||
|
Version 1.0, April 4 1999.
|
||
|
Harm van der Heijden (H.v.d.Heijden@phys.tue.nl)
|
||
|
|
||
|
P.S. Check out the string module. It's imported in this sample not
|
||
|
because it's used, but because it's so beautifully documented...
|
||
|
"""
|
||
|
|
||
|
from wxPython import wx
|
||
|
import string # Don't use it, but it's fun expanding :-)
|
||
|
|
||
|
#----------------------------------------------------------------------
|
||
|
|
||
|
def _getindent(line):
|
||
|
"""Returns the indentation level of the given line."""
|
||
|
indent = 0
|
||
|
for c in line:
|
||
|
if c == ' ': indent = indent + 1
|
||
|
elif c == '\t': indent = indent + 8
|
||
|
else: break
|
||
|
return indent
|
||
|
|
||
|
def _sourcefinder(func):
|
||
|
"""Given a func_code object, this function tries to find and return
|
||
|
the python source code of the function."""
|
||
|
try:
|
||
|
f = open(func.co_filename,"r")
|
||
|
except:
|
||
|
return "(could not open file %s)" % (func.co_filename,)
|
||
|
|
||
|
for i in range(func.co_firstlineno):
|
||
|
line = f.readline()
|
||
|
ind = _getindent(line)
|
||
|
msg = ""
|
||
|
while line:
|
||
|
msg = msg + line
|
||
|
line = f.readline()
|
||
|
# the following should be <= ind, but then we get
|
||
|
# confused by multiline docstrings. Using == works most of
|
||
|
# the time... but not always!
|
||
|
if _getindent(line) == ind: break
|
||
|
return msg
|
||
|
|
||
|
#----------------------------------------------------------------------
|
||
|
|
||
|
class pyTree(wx.wxTreeCtrl):
|
||
|
"""
|
||
|
This wxTreeCtrl derivative displays a tree view of a Python namespace.
|
||
|
Anything from which the dir() command returns a non-empty list is a branch
|
||
|
in this tree.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, parent, id, root):
|
||
|
"""
|
||
|
Initialize function; because we insert branches into the tree
|
||
|
as needed, we use the ITEM_EXPANDING event handler. The
|
||
|
ITEM_COLLAPSED handler removes the stuff afterwards. The
|
||
|
SEL_CHANGED handler attempts to display interesting
|
||
|
information about the selected object.
|
||
|
"""
|
||
|
wx.wxTreeCtrl.__init__(self, parent, id)
|
||
|
self.root = self.AddRoot(str(root), -1, -1, wx.wxTreeItemData(root))
|
||
|
if dir(root):
|
||
|
self.SetItemHasChildren(self.root, wx.TRUE)
|
||
|
wx.EVT_TREE_ITEM_EXPANDING(self, self.GetId(), self.OnItemExpanding)
|
||
|
wx.EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemCollapsed)
|
||
|
wx.EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
|
||
|
self.output = None
|
||
|
|
||
|
|
||
|
def SetOutput(self, output):
|
||
|
"""
|
||
|
Set output function (accepts single string). Used to display string
|
||
|
representation of the selected object by OnSelChanged.
|
||
|
"""
|
||
|
self.output = output
|
||
|
|
||
|
|
||
|
def OnItemExpanding(self,event):
|
||
|
"""
|
||
|
The real workhorse of this class. First we retrieve the object
|
||
|
(parent) belonging to the branch that is to be expanded. This
|
||
|
is done by calling GetPyData(parent), which is a short-cut for
|
||
|
GetPyItemData(parent).Get().
|
||
|
|
||
|
Then we get the dir() list of that object. For each item in
|
||
|
this list, a tree item is created with associated
|
||
|
wxTreeItemData referencing the child object. We get this
|
||
|
object using child = getattr(parent, item).
|
||
|
|
||
|
Finally, we check wether the child returns a non-empty dir()
|
||
|
list. If so, it is labeled as 'having children', so that it
|
||
|
may be expanded. When it actually is expanded, this function
|
||
|
will again figure out what the offspring is.
|
||
|
"""
|
||
|
item = event.GetItem()
|
||
|
obj = self.GetPyData( item )
|
||
|
lst = dir(obj)
|
||
|
for key in lst:
|
||
|
new_obj = getattr(obj,key)
|
||
|
new_item = self.AppendItem( item, key, -1, -1,
|
||
|
wx.wxTreeItemData(new_obj) )
|
||
|
if dir(new_obj):
|
||
|
self.SetItemHasChildren(new_item, wx.TRUE)
|
||
|
|
||
|
def OnItemCollapsed(self, event):
|
||
|
"""
|
||
|
We need to remove all children here, otherwise we'll see all
|
||
|
that old rubbish again after the next expansion.
|
||
|
"""
|
||
|
item = event.GetItem()
|
||
|
self.DeleteChildren(item)
|
||
|
|
||
|
def OnSelChanged(self, event):
|
||
|
"""
|
||
|
If an output function is defined, we try to print some
|
||
|
informative, interesting and thought-provoking stuff to it.
|
||
|
If it has a __doc__ string, we print it. If it's a function or
|
||
|
unbound class method, we attempt to find the python source.
|
||
|
"""
|
||
|
if not self.output:
|
||
|
return
|
||
|
obj = self.GetPyData( event.GetItem() )
|
||
|
msg = str(obj)
|
||
|
if hasattr(obj, '__doc__'):
|
||
|
msg = msg+"\n\nDocumentation string:\n\n%s" % ( getattr(obj, '__doc__'),)
|
||
|
# Is it a function?
|
||
|
func = None
|
||
|
if hasattr(obj, "func_code"): # normal function
|
||
|
func = getattr(obj, "func_code")
|
||
|
elif hasattr(obj, "im_func"): # unbound class method
|
||
|
func = getattr(getattr(obj, "im_func"), "func_code")
|
||
|
if func: # if we found one, let's try to print the source
|
||
|
msg = msg+"\n\nFunction source:\n\n" + _sourcefinder(func)
|
||
|
|
||
|
apply(self.output, (msg,))
|
||
|
|
||
|
#----------------------------------------------------------------------
|
||
|
|
||
|
overview = __doc__
|
||
|
|
||
|
def runTest(frame, nb, log):
|
||
|
split = wx.wxSplitterWindow(nb, -1)
|
||
|
tree = pyTree(split, -1, __main__)
|
||
|
text = wx.wxTextCtrl(split, -1, "", wx.wxDefaultPosition,
|
||
|
wx.wxDefaultSize, wx.wxTE_MULTILINE)
|
||
|
split.SplitVertically(tree, text, 200)
|
||
|
tree.SetOutput(text.SetValue)
|
||
|
tree.SelectItem(tree.root)
|
||
|
text.SetBackgroundColour(wxNamedColour("LIGHT BLUE"))
|
||
|
tree.SetBackgroundColour(wxNamedColour("LIGHT BLUE"))
|
||
|
|
||
|
return split
|
||
|
|
||
|
|
||
|
|
||
|
#----------------------------------------------------------------------
|
||
|
if __name__ == '__main__':
|
||
|
|
||
|
class MyFrame(wx.wxFrame):
|
||
|
"""Very standard Frame class. Nothing special here!"""
|
||
|
|
||
|
def __init__(self):
|
||
|
"""Make a splitter window; left a tree, right a textctrl. Wow."""
|
||
|
import __main__
|
||
|
wx.wxFrame.__init__(self, wx.NULL, -1, "PyTreeItemData Test",
|
||
|
wx.wxDefaultPosition, wx.wxSize(800,500))
|
||
|
split = wx.wxSplitterWindow(self, -1)
|
||
|
tree = pyTree(split, -1, __main__)
|
||
|
text = wx.wxTextCtrl(split, -1, "", wx.wxDefaultPosition,
|
||
|
wx.wxDefaultSize, wx.wxTE_MULTILINE)
|
||
|
split.SplitVertically(tree, text, 200)
|
||
|
tree.SetOutput(text.SetValue)
|
||
|
tree.SelectItem(tree.root)
|
||
|
|
||
|
class MyApp(wx.wxApp):
|
||
|
"""This class is even less interesting than MyFrame."""
|
||
|
|
||
|
def OnInit(self):
|
||
|
"""OnInit. Boring, boring, boring!"""
|
||
|
frame = MyFrame()
|
||
|
frame.Show(wx.TRUE)
|
||
|
self.SetTopWindow(frame)
|
||
|
return wx.TRUE
|
||
|
|
||
|
app = MyApp(0)
|
||
|
app.MainLoop()
|
||
|
|
||
|
|