recursive iterator, frame controls traversal

Hi all,

I have wxFrame with a bunch of controls (splitter window, tool bar,
panes, trees, list controls...) and I want to traverse the entire
object tree looking for all the controls that are wxTreeControls. I
apparently do not understand how the generators/iterators work with
recursion, and would like some help.

I have a generator traverse:

def traverse( node ):
    print "+traverse"
    kids = node.GetChildren()
    for kid in kids:
        traverse( kid )
        print "yield kid = ", kid
        yield kid

and I call it thusly:
     t = traverse( frame )
    for n in t:
        print "node = ", n

but it only results in the top two objects being returned -- the top
level descendants of the frame.

However, if I remove the yield statement, I get full tree
traversal...Obviously, I'm missing something -- anyone clear this up
for me? All help appreciated.

:bp:

Hi,

···

On Feb 22, 2010, at 7:15 PM, billy pilgrim wrote:

and I call it thusly:
t = traverse( frame )
for n in t:
print "node = ", n

A generator method should be iterated over, if you want to use the code like you have above you should make the method generate and return a list.

for n in traverse(frame):

print "node = ", n

Cody

You are recursively calling traverse as if it was a function, but it isn't. It's a generator. Something like this may do it:

def traverse(node):
     for child in node.GetChildren():
         yield child
         for grandchild in traverse(child):
             yield grandchild

Although simply building a list and returning it would be simpler from a conceptual viewpoint, and since all the nodes are already present, will likely always be a fairly small collection, and nothing needs to be "generated" then there is no real performance hit either:

def traverse(node):
     L = [node]
     for child in node.GetChildren():
         L += traverse(child)
     return L

···

On 2/22/10 5:15 PM, billy pilgrim wrote:

Hi all,

I have wxFrame with a bunch of controls (splitter window, tool bar,
panes, trees, list controls...) and I want to traverse the entire
object tree looking for all the controls that are wxTreeControls. I
apparently do not understand how the generators/iterators work with
recursion, and would like some help.

I have a generator traverse:

def traverse( node ):
     print "+traverse"
     kids = node.GetChildren()
     for kid in kids:
         traverse( kid )
         print "yield kid = ", kid
         yield kid

but it only results in the top two objects being returned -- the top
level descendants of the frame.

However, if I remove the yield statement, I get full tree
traversal...Obviously, I'm missing something -- anyone clear this up
for me? All help appreciated.

--
Robin Dunn
Software Craftsman

Thank you everyone!

Robin's solution (building a list) works quite well.

FWIW: there is no GetClassInfo support (that I could find), but
node.ClassName == 'wxPyTreeCtrl' found all my tree controls. Now, on
to the next windmill.

Cody: I tried your suggestion but I couldn't make it work, so I took
Robin's.

Thanks everyone, for your help, and for supporting wxPython.
Hopefully, I will eventually be able to help someone else.

:bp:

···

On Feb 22, 9:25 pm, Robin Dunn <ro...@alldunn.com> wrote:

On 2/22/10 5:15 PM, billy pilgrim wrote:

> Hi all,

> I have wxFrame with a bunch of controls (splitter window, tool bar,
> panes, trees, list controls...) and I want to traverse the entire
> object tree looking for all the controls that are wxTreeControls. I
> apparently do not understand how the generators/iterators work with
> recursion, and would like some help.

> I have a generator traverse:

> def traverse( node ):
> print "+traverse"
> kids = node.GetChildren()
> for kid in kids:
> traverse( kid )
> print "yield kid = ", kid
> yield kid
> but it only results in the top two objects being returned -- the top
> level descendants of the frame.

> However, if I remove the yield statement, I get full tree
> traversal...Obviously, I'm missing something -- anyone clear this up
> for me? All help appreciated.

You are recursively calling traverse as if it was a function, but it
isn't. It's a generator. Something like this may do it:

def traverse(node):
for child in node.GetChildren():
yield child
for grandchild in traverse(child):
yield grandchild

Although simply building a list and returning it would be simpler from a
conceptual viewpoint, and since all the nodes are already present, will
likely always be a fairly small collection, and nothing needs to be
"generated" then there is no real performance hit either:

def traverse(node):
L = [node]
for child in node.GetChildren():
L += traverse(child)
return L

--
Robin Dunn
Software Craftsmanhttp://wxPython.org

Or you could do it the Python way with isinstance(node, wx.TreeCtrl).

···

On 2/23/10 6:59 AM, billy pilgrim wrote:

FWIW: there is no GetClassInfo support (that I could find), but
node.ClassName == 'wxPyTreeCtrl' found all my tree controls.

--
Robin Dunn
Software Craftsman