Navigating the tree programmatically

In section 15.1 we mentioned that there was no direct way to get a Python list of the children of a given item in the tree, let alone the index of a specific child. To do that, you need to walk the tree nodes yourself using the methods in this section.

To start walking the tree, get the root using GetRootItem(). This method returns the wx.TreeItemId of the root item of the tree. You can then use methods such as GetItemText() or GetItemPyData() to retrieve more information about the item.

Once you have an item, getting its children involves a kind of an iterator which lets you walk through the list of children one by one. You get the first child in the subtree with the method GetFirstChild(item) which returns a two-element tuple (child, cookie). The item is the wx.TreeItemId of the first child, and the second is a special token value. In addition to telling you what the first child is, this method initializes an iterator object that allows you to walk through the tree. The cookie value is just a token that allows the tree control to keep track of multiple iterators on the same tree at the same time without them interfering with each other.

Once you have the cookie from GetFirstChild(), you can get the rest of the children by repeatedly calling GetNextChild(item, cookie). The item is the ID of the parent tree item, and the cookie is the cookie as returned by GetFirstChild() or the previous call to GetNextChild(). The GetNextChild() method returns a two-element tuple (child, cookie) . If there is no next child, you've reached the end of the child list, and the system returns an invalid child ID. You can test this by using the method wx.TreeItemId.IsOk(), or using the Python shortcut ofjust testing the item, since it has a magic __nonzero__ method. The following helper function returns a list of the text for each child of a given tree item.

def getChildren(tree, parent): result = []

item, cookie = tree.GetFirstChild(parent) while item:

result.append(tree.GetItemText(item))

item, cookie = tree.getNextChild(parent, cookie) return result

This method gets the first child of the given parent item, adds its text to the list, then loops through the child items until it gets an invalid item, at which point it returns the result. The order in which items are displayed is based on the current display state of the tree—you will get the items in the exact order of the current display from top to bottom.

To cut right to the end and get the last child for a given parent, you can use the method GetLastChild(item), which returns the wx.TreeItemId of the last item in the list. Since this method is not used to drive an iterator through the entire child list, it does not need the cookie mechanism. If you have the child and you want the parent, the method GetItemParent(item) will return the tree ID of the parent of the given item.

You can walk back and forth between items at the same level using the methods GetNextSibling(item), and GetPrevSibling(item). These methods return the tree ID of the appropriate item. Since these methods are also not used to drive iterators, they do not need a cookie. If there is no next or previous item because you have reached the end of the list, the method returns an invalid item (i.e., item.IsOk() == False.

To determine if an item has any children, use the method ItemHasChil-dren(item) which returns a Boolean True or False. You can set whether an item has children using the method SetItemHasChildren(item, hasChildren=True) . If an item has its children property set to True, it will display onscreen as though it had children, even if there are no actual children. This means that the item will have the appropriate button next to it, allowing it to be collapsed or expanded even if there is nothing to actually show by expanding the item. This is used to implement a virtual tree control where not all items logically in the tree have to physically be there, saving runtime resources. This technique is demonstrated in section 15.7.