On Tue, Jul 06, 2004 at 12:06:28PM -0700, John Finlay wrote:
> In addition to receiving comments about tutorial problems, errors and
> enhancements, I'm interested in hearing from poeple who have used the
> GenericTreeModel. Specifically, I'm interested in what applications
> require a custom tree model instead of the standard ones, and what
> issues they encountered developing and using a custom tree model. Same
> for the GenericCellRenderer.
Attached is a GenericCellRenderer that I used in my Classicollect app
(ripped out of context and simplified a bit), but not shown is the important
part where you have to take care of sending all the
row-insert/changed/deleted etc. signals. Note that it doesn't do the
subclassing quite correctly. I could fix this up into a simple working
example if anyone is interested.
Essentially I implemented this tree (really a forest) the way we were taught
in school: each tree node has its cargo, a reference to the parent node, and
a list of child nodes.
I also keep an index for each node, which is its position its parent's child
list, for efficiently finding the path of a node. Since get_path doesn't
seem to get called much (by treeviews anyway), this may not be necessary,
and it does add some extra bookkeeping if you remove or insert nodes.
I originally wrote this because I didn't know about
TreeViewColumn.set_cell_data_func, and, well, writing a GTM is kinda fun.
Then I went back to it when I found that cell_data_funcs wouldn't work with
interactive searches (there was no TreeView.set_search_func in pygtk at the
time; when I found out about that it was fixed by gjc within the day!) or
with the new ComboBoxes. Now with TreeModelFilter, I don't think I have any
need for a generic TreeModel, though I haven't had a chance to really test
it with a large data set. And if this works:
http://bugzilla.gnome.org/show_bug.cgi?id=144509
you have yet another easy way to write a custom TreeStore.
import pygtk; pygtk.require('2.0')
import gtk
# Schematically, nodes look something like this:
class Node:
def __init__(self, parent=None, children=None, data=None,
index=0, level=None):
self.parent = parent
if children is None: self.children = []
if data is None: self.data = {} # node cargo
self.index = index # index of child
self.level = level # provides info about each depth of the tree
OUTFILE = sys.stdout
def print_debug(*args):
for arg in args:
print >>OUTFILE, arg,
print >>OUTFILE
OUTFILE.flush()
class PyListTreeModel(gtk.GenericTreeModel):
'''A TreeModel using Node objects as its base data structure.'''
def __init__(self, root, *column_types):
'''constructor for the model. Make sure you call
PyTreeModel.__init__'''
gtk.GenericTreeModel.__init__(self)
self.set_property("leak_references", 0)
self.column_types = column_types
self.ncolumns = len(self.column_types)
self.root = root
def on_get_flags(self):
'''returns the GtkTreeModelFlags for this particular type of model'''
print_debug("on_get_flags")
return 0
def on_get_n_columns(self):
'''returns the number of columns in the model'''
print_debug("on_get_n_columns")
return self.ncolumns
def on_get_column_type(self, index):
'''returns the type of a column in the model'''
print_debug("on_get_column_type", index)
t = self.column_types[index]
return t
def on_get_path(self, node):
'''returns the tree path (a tuple of indices at the various
levels) for a particular node.'''
print_debug("on_get_path", node)
path = []
while node.parent:
path.append(node.index)
node = node.parent
path.reverse()
return tuple(path)
def on_get_iter(self, path):
'''returns the node corresponding to the given path'''
print_debug("on_get_iter:", path)
node = self.root
try:
for i in path:
node = node.children[i]
except IndexError:
node = None
return node
def on_get_value(self, node, i):
'''returns the value stored in a particular column for the node'''
print_debug("on_get_value:", node, i)
level = node.level
try:
value = node.data[level.keys[i]]
except KeyError:
value = level.control_cols[i]
return value
def on_iter_next(self, node):
'''returns the next node at this level of the tree'''
print_debug("on_iter_next", node)
siblings = node.parent.children
try:
next = siblings[node.index+1]
except IndexError:
next = None
return next
def on_iter_children(self, node):
'''returns the first child of this node'''
print_debug("on_iter_children", node)
try:
child = node.children[0]
except IndexError:
child = None
return child
def on_iter_has_child(self, node):
'''returns true if this node has children'''
print_debug("on_iter_has_child", node)
return len(node.children) > 0
def on_iter_n_children(self, node):
'''returns the number of children of this node'''
print_debug("on_iter_n_children", node)
return len(node.children)
def on_iter_nth_child(self, node, n):
'''returns the nth child of this node'''
print_debug("on_iter_nth_child", node)
try:
nth_child = node.children[n]
except (AttributeError, IndexError):
nth_child = None
return nth_child
def on_iter_parent(self, node):
'''returns the parent of this node'''
print_debug("on_iter_parent", node)
if not node or node.parent is self.root:
parent = None
else:
parent = node.parent
return parent
_______________________________________________
pygtk mailing list [EMAIL PROTECTED]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/