Controlling TreeCtrl Structure with additional data

Hi, I have a project that requires a tree control be used to keep track of
groups of items.

Previously I have written a small routine to load and save the data from a
tree control, however, in that particular instance there was a limit to the
number of sub trees. That is no longer the case.

To cause further problems each item in the tree requires additional data
associated with it in the form of a string, that remains unseen but which is
used frequently.

I thought that the easiest method would be to maintain an array (list) of
the items, along with their data, however, I have failed to work out any
method of keeping track of the tree structure, let alone save it and reload
it along with its data.

I need to be able to save the tree structure (and it WILL change during
use), and to be able to reload that structure when needed, but the structure
file must also be able to contain the data for each item, and process and
load that data for use when the file is loaded.

Iv seen a couple of example editor programs that seem to do this, but my
python is not strong enough to decipher what is being done.

Can anyone point me in the right direction please, perhaps with some example
code of storing and restoring the tree structure from an array etc.

Regards

MVK

···

--
View this message in context: http://www.nabble.com/Controlling-TreeCtrl-Structure-with-additional-data-tp22398485p22398485.html
Sent from the wxPython-users mailing list archive at Nabble.com.

MaxVK wrote:

Hi, I have a project that requires a tree control be used to keep track of
groups of items.

Previously I have written a small routine to load and save the data from a
tree control, however, in that particular instance there was a limit to the
number of sub trees. That is no longer the case.

To cause further problems each item in the tree requires additional data
associated with it in the form of a string, that remains unseen but which is
used frequently.

I thought that the easiest method would be to maintain an array (list) of
the items, along with their data, however, I have failed to work out any
method of keeping track of the tree structure, let alone save it and reload
it along with its data.

I need to be able to save the tree structure (and it WILL change during
use), and to be able to reload that structure when needed, but the structure
file must also be able to contain the data for each item, and process and
load that data for use when the file is loaded.

Iv seen a couple of example editor programs that seem to do this, but my
python is not strong enough to decipher what is being done.

Can anyone point me in the right direction please, perhaps with some example
code of storing and restoring the tree structure from an array etc.

Regards

MVK
  

TreeCtrl items can have a TreeDataItem associated with them, which is a wrapper around an object, basically.
I also store a list which stores the references to each node in the tree

i.e, _id is an integer:

        data = wx.TreeItemData(_id)
        t = self.tree.AppendItem(self.root, "Tab " + str(_id + 1), data=data)
        self.tabs[_id] = t

self.tabs keeps a list of TreeItemIDs

then, to receive the data back:

    def on_click(self, event):
        """
        Changes to the selected tab is a tab node is double clicked upon,
        otherwise pops up the
        """
        item = self.tree.GetPyData(event.GetItem())

        if not item:
            return # click on the root node

        if isinstance(item, int):
            self.gui.tabs.SetSelection(item)

Hopefully that should give you an idea. I store relatively objects that I have defined myself in my data tree, that just contain simply Python data structures, so it's a matter of saving that list of objects and then loading them back into the tree by re-creating its TreeDataItem (I don't persist that)

- Steven Sproat

Steven Sproat wrote:

TreeCtrl items can have a TreeDataItem associated with them, which is a
wrapper around an object, basically.
I also store a list which stores the references to each node in the tree

i.e, _id is an integer:

        data = wx.TreeItemData(_id)
        t = self.tree.AppendItem(self.root, "Tab " + str(_id + 1),
data=data)
        self.tabs[_id] = t

self.tabs keeps a list of TreeItemIDs

then, to receive the data back:

    def on_click(self, event):
        """
        Changes to the selected tab is a tab node is double clicked upon,
        otherwise pops up the
        """
        item = self.tree.GetPyData(event.GetItem())

        if not item:
            return # click on the root node

        if isinstance(item, int):
            self.gui.tabs.SetSelection(item)

Hopefully that should give you an idea. I store relatively objects that
I have defined myself in my data tree, that just contain simply Python
data structures, so it's a matter of saving that list of objects and
then loading them back into the tree by re-creating its TreeDataItem (I
don't persist that)

Thanks Steven, I appreciate your time, however, to my shame, I must admit
that I am unable to follow your example particularly well, or rather, I
should say, I am unable to translate it to fit into my own code.

For example:

import wx

class clsMainFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.panel_OutMain = wx.Panel(self, -1,
style=wx.SUNKEN_BORDER|wx.TAB_TRAVERSAL)
        self.tTREE = wx.TreeCtrl(self.panel_OutMain, -1,
style=wx.TR_HAS_BUTTONS|wx.TR_NO_LINES|wx.TR_DEFAULT_STYLE|wx.SUNKEN_BORDER)
        self.__set_properties()
        self.__do_layout()
        troot = self.tTREE.AddRoot("Main Item")
        tchild1 = self.tTREE.AppendItem(troot,"First Child Item")
        tchild1a = self.tTREE.AppendItem(tchild1,"Sub item one")
        tchild1b = self.tTREE.AppendItem(tchild1,"Sub item two")
        tchild1ba = self.tTREE.AppendItem(tchild1b,"Sub Sub item one")
        tchild2 = self.tTREE.AppendItem(troot,"Second Child item")
        tchild2a = self.tTREE.AppendItem(tchild2,"Sub item one")

···

#
#
    def __set_properties(self):
        self.SetTitle("MainFrame")
        self.SetSize((400, 300))
#
#
    def __do_layout(self):
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_1.Add(self.panel_OutMain, 1, wx.ALL|wx.EXPAND, 2)
        sizer_2.Add(self.tTREE, 1, wx.ALL|wx.EXPAND, 2)
        self.panel_OutMain.SetSizer(sizer_2)
        self.SetSizer(sizer_1)
        self.Layout()
        self.Centre()
#
#
if __name__ == "__main__":
    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    MainFrame = clsMainFrame(None, -1, "")
    app.SetTopWindow(MainFrame)
    MainFrame.Show()
    app.MainLoop()

This is how my app is laid out.
The dummy tree structure can be saved to a file and loaded back again.

This however, is where the problems start. In the example above I want to be
able to add some dummy text as data for each item. I *think* I managed to
follow your code enough to add an integer ID to the TreeDataItem as I added
them to the tree. I also added this ID to an array, along with the dummy
text that I wanted to use.

However, if I tried to retrieve the data ID from the item that was clicked
(so that I could match the ID in the data list and get the data string), I
could not seem to get to the integer that should have been there as an ID.

Am I even following the right tracks here? I think I am (from looking at
your code), but for the life of me I cant seem to work out how to get the
integer back from the TreeDataItem so that I can match it up with the
correct item in the data list.

Sorry to be so dense, but if I don't ask Ill never know!

regards

MVK
--
View this message in context: http://www.nabble.com/Controlling-TreeCtrl-Structure-with-additional-data-tp22398485p22403888.html
Sent from the wxPython-users mailing list archive at Nabble.com.

MaxVK wrote:

that I am unable to follow your example particularly well, or rather, I
should say, I am unable to translate it to fit into my own code.

For example:

This is how my app is laid out.
The dummy tree structure can be saved to a file and loaded back again.

This however, is where the problems start. In the example above I want to be
able to add some dummy text as data for each item. I *think* I managed to
follow your code enough to add an integer ID to the TreeDataItem as I added
them to the tree. I also added this ID to an array, along with the dummy
text that I wanted to use.

However, if I tried to retrieve the data ID from the item that was clicked
(so that I could match the ID in the data list and get the data string), I
could not seem to get to the integer that should have been there as an ID.

Am I even following the right tracks here? I think I am (from looking at
your code), but for the life of me I cant seem to work out how to get the
integer back from the TreeDataItem so that I can match it up with the
correct item in the data list.

Sorry to be so dense, but if I don't ask Ill never know!

regards

MVK
  Thanks Steven, I appreciate your time, however, to my shame, I must admit

It's okay. For one, you're not binding any events to your tree, so you can't respond to any events.
Whoops, I guess I left that out, but you didn't provide any code so I assumed you had at least done that.

I did:

self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.on_click)

that bound double click to any element in the tree
if you've done that in your application, you must do something like

data = wx.TreeDataItem(your_object)
tree.AppendItem(node, "text", data=data)

when you append the item (see below), and in on_click:

def on_click(self, event):
item = self.tree.GetPyData(event.GetItem())
#do whatever with item.

so that the tree node stores an internal reference to the object you wish to store
in the on_click method then, item is being assigned to the object you stored inside the DataItem

I noticed item is None if the root node is double clicked

hope that helps,
steve

Steven Sproat wrote:

It's okay. For one, you're not binding any events to your tree, so you
can't respond to any events.
Whoops, I guess I left that out, but you didn't provide any code so I
assumed you had at least done that.

I did:

self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.on_click)

that bound double click to any element in the tree
if you've done that in your application, you must do something like

data = wx.TreeDataItem(your_object)
tree.AppendItem(node, "text", data=data)

when you append the item (see below), and in on_click:

def on_click(self, event):
item = self.tree.GetPyData(event.GetItem())
#do whatever with item.

so that the tree node stores an internal reference to the object you
wish to store
in the on_click method then, item is being assigned to the object you
stored inside the DataItem

I noticed item is None if the root node is double clicked

hope that helps,
steve

Ah, it makes more sense now! I did have events bound, that bit of code was a
(hastily) thrown together example to show how things were laid out (Its from
a template - all I did was throw on the tree), and I plain forgot to add the
events to it.

It was actually retrieving the data that was throwing me out but I ended up
using :
xID = self.tTREE.GetItemData(tItem).GetData() where tItem was passed to the
routine from an EVT_TREE_SEL_CHANGED event.

I added the actual data and its ID to an array, which I can then match up to
get what I need.

Thanks very much for your help Steven, its very much appreciated.

regards

MVK

···

--
View this message in context: http://www.nabble.com/Controlling-TreeCtrl-Structure-with-additional-data-tp22398485p22413303.html
Sent from the wxPython-users mailing list archive at Nabble.com.