wx.TreeCtrl doesn't work when using EVT_TREE_ITEM_EXPANDING

Hello,

I have the following issue:

I created a tool using wx.TreeCtrl to show the content of a subversion repository.

When I create the TreeCtrl, I have a function named update_tree shown below

def update_tree(self, projectname, projecttree, usergroups, parentgroups):
    self.usergroups = set(usergroups)
    self.parentgroups = set(parentgroups)
    self.parentgroups -= self.usergroups
    try:
        self.Freeze()
    except Exception as e:
        pass
    super().update_tree(projectname, projecttree)
    # now scan through all the items and set the images accordingly
    self.set_image(self._root)
    self.treewalk(self._root, self.set_image, childs_only=True)
    try:
        self.Thaw()
    except Exception as e:
        pass

def treewalk(self, parent, pre_fct=None, post_fct=None, childs_only=False):
    child, cookie = self.GetFirstChild(parent)
    while child.IsOk():
        descend = False
        if pre_fct:
            descend = pre_fct(child)
        if descend and self.ItemHasChildren(child) and not childs_only:
            self.treewalk(child, pre_fct, post_fct, childs_only)
        if post_fct:
            post_fct(parent)
        child, cookie = self.GetNextChild(parent, cookie)

That calls a treewalk function which basically goes through all elements in the TreeCtrl and it's children, then for each item calls a function set_image.
This function determines which icon is going to be used for that element.

This works fine. So far, so good.

But it takes quite a while to process the entire tree with lots of nodes (our largest repository contains over 1.7 million nodes).

So I had this idea of using the EVT_TREE_ITEM_EXPANDING functionality. So I only display the node and it's children, then only when a child is clicked, the tree item expands and for each child the function
is called to determine the icon. So I added the flag childs_only in the treewalk function.
My expandItem function looks as follows:

def expanditem(self,event):
    self.selected = event.GetItem()
    self.selectionString = self.GetItemText(self.selected)
    print('TREE_SEL_EXPANDING in projectTree on {}'.format(self.selectionString))
    self.treewalk(self.selected, self.set_image, childs_only=True)

The problem I run into is that when the expanditem is called on a node, the self.selected is OK, the selectionString is OK, but when I try to run the treewalk function,
nothing happens. The item (although it does contain children) does not expand.

For some reason, the line child.IsOk() returns False.

Running the code with childs_only set to FALSE, and ignoring the expandItem function, everything works.
With childs_only set to TRUE and using the expand, the child.isOK returns FALSE.

If anyone has an idea on why, I'd really appreciate some input.

Thank you very much.

 

I finally figured it out.

I document this further, because it may perhaps help other wxpython users.

Root cause was the parent class, who called self.Expand(self._root), which triggered the expanditem function.

But at this time, no access configuration was loaded yet. So the item was CollapseAndReset !!

After the Expand call to the root, the information needed to correctly determine the icons was ‘loaded’.

Then the class itself calls the treewalk function which changes the icon, giving the impression one can go deeper.

So when clicking the item, the expand function was triggered, but the item was CollapseAndReset, causing the child.IsOk to fail.

Solution to this issue was to first load the information needed to determine the icons, then to call the self.Expand(self._root)

It also explains the behaviour. When not using the expand functionality, the self.Expand(self._root) does not change the state of the item.

Then when the icon information is available, the treewalk results in correct behaviour.

···

On Wednesday, June 27, 2018 at 8:37:07 PM UTC+2, Blue Flash wrote:

Hello,

I have the following issue:

I created a tool using wx.TreeCtrl to show the content of a subversion repository.

When I create the TreeCtrl, I have a function named update_tree shown below

def update_tree(self, projectname, projecttree, usergroups, parentgroups):
    self.usergroups = set(usergroups)
    self.parentgroups = set(parentgroups)
    self.parentgroups -= self.usergroups
    try:
        self.Freeze()
    except Exception as e:
        pass
    super().update_tree(projectname, projecttree)
    # now scan through all the items and set the images accordingly
    self.set_image(self._root)
    self.treewalk(self._root, self.set_image, childs_only=True)
    try:
        self.Thaw()
    except Exception as e:
        pass



def treewalk(self, parent, pre_fct=None, post_fct=None, childs_only=False):
    child, cookie = self.GetFirstChild(parent)
    while child.IsOk():
        descend = False
        if pre_fct:
            descend = pre_fct(child)
        if descend and self.ItemHasChildren(child) and not childs_only:
            self.treewalk(child, pre_fct, post_fct, childs_only)
        if post_fct:
            post_fct(parent)
        child, cookie = self.GetNextChild(parent, cookie)

That calls a treewalk function which basically goes through all elements in the TreeCtrl and it's children, then for each item calls a function set_image.
This function determines which icon is going to be used for that element.

This works fine. So far, so good.

But it takes quite a while to process the entire tree with lots of nodes (our largest repository contains over 1.7 million nodes).

So I had this idea of using the EVT_TREE_ITEM_EXPANDING functionality. So I only display the node and it's children, then only when a child is clicked, the tree item expands and for each child the function
is called to determine the icon. So I added the flag childs_only in the treewalk function.
My expandItem function looks as follows:

def expanditem(self,event):
    self.selected = event.GetItem()
    self.selectionString = self.GetItemText(self.selected)
    print('TREE_SEL_EXPANDING in projectTree on {}'.format(self.selectionString))
    self.treewalk(self.selected, self.set_image, childs_only=True)


The problem I run into is that when the expanditem is called on a node, the self.selected is OK, the selectionString is OK, but when I try to run the treewalk function,
nothing happens. The item (although it does contain children) does not expand.

For some reason, the line child.IsOk() returns False.

Running the code with childs_only set to FALSE, and ignoring the expandItem function, everything works.
With childs_only set to TRUE and using the expand, the child.isOK returns FALSE.

If anyone has an idea on why, I'd really appreciate some input.

Thank you very much.