Search code examples
pythonwxpython

TreeItemId obtained from TreeEvent is not the same as obtained from AppendItem


I am building a program that will store some complex objects, and I am using wxPython for the UI. The objects hierarchy will have a tree representation (TreeCtrl). I am using a dictionary to map objects from the UI to the database, using the TreeItemIds returned by AppendItem as keys and the objects themselves as values (actually I am not using the objects as values, but it simplifies the problem). The following snippet exemplifies what I am trying to do:

import wx

class ComplexObject(object):
    def __init__(self, name, otherdata):
        self.name = name
        self.otherdata = otherdata

class TestFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        super(TestFrame, self).__init__(*args, **kwargs)

        self.tree = wx.TreeCtrl(self)
        self.rootid = self.tree.AddRoot("Root")
        self.tree.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.onrightclick)

        self.objectmap = {}

    def addobject(self, obj):
        itemid = self.tree.AppendItem(self.rootid, obj.name)
        self.objectmap[itemid] = obj

    def onrightclick(self, event):
        itemid = event.GetItem()
        if itemid == self.rootid:
            return
        obj = self.objectmap[itemid]
        print "Do something with ComplexObject {}".format(obj.name)

if __name__ == '__main__':
    app = wx.App(False)
    testframe = TestFrame(None)

    for i in range(3):
        obj = ComplexObject('obj{}'.format(i), i)
        testframe.addobject(obj)

    testframe.Show()
    app.MainLoop()

When I right-click an entry in the tree I get a KeyError, because the object I get from the event (itemid = event.GetItem()) is not the same I get when I add an item (itemid = self.tree.AppendItem(self.rootid, obj.name)). Is this the expected behavior? How should I proceed to achieve what I am trying to do? I am starting to experiment with SetPyData and GetPyData, but I hope there is a better way to do that.

Thank you very much.

Platform Information: MS Windows 7, Python 2.7.9, wxPython 2.8.12.1


Solution

  • Yes, it is expected.

    You can think of the TreeItemId as a closed box with an implementation dependent handle inside, and that the treectrl is the only one that can open the box to get the handle out. You may see different boxes at different times for the same tree item, but they will all have the same handle inside. But since the handle itself is an implementation detail there is no program access to it.

    Using SetPyData to associate data to tree items is the proper way to do things like this. If you want to keep your associated data in a separate dictionary then you could generate unique dictionary keys when adding the items, and then pass they key to SetPyData, and use GetPyData to fetch the key later when you need to fetch the value object from the dictionary.