Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Set TreeView values dynamically

    Scheduled Pinned Locked Moved PYTHON Development
    9 Posts 0 Posters 2.7k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      Helper
      last edited by

      On 12/04/2018 at 08:21, xxxxxxxx wrote:

      Hi everyone,

      I was having a bit of experimentation with the TreeView custom GUI, which btw is preety awesome, but having some difficulty in setting the values correctly to each column.

      So will explain the ideas/problems that I have which hopefully someone will be able to help.

      Process 1: You add the selected objects to a list, by pressing the "Add" button.

      Process 2:  Each selected object and values populate the list, in the correct column.
      Issue 2: When I create a list, can't distribute the values correctly to each column. As per the final result example above.

      It may be related with some of the code below (taken from a good example by Maxime: https://developers.maxon.net/forum/topic/10654/14102_using-customgui-listview&KW=tree&PID=56287#56287)

      I can see that only works for one value, but would like set the 3 values.

          
          
          class PickObjs(object) :
          
              objSel = ""
              _selected = False
          
              def __init__(self, objSel) :
          
                  self.objSel = objSel
                  print self.objSel <-- PRINTS CORRECTLY THE OBJECT AND VALUES!
          
              @property
              def IsSelected(self) :
                  return self._selected
          
              def Select(self) :
                  self._selected = True
          
              def Deselect(self) :
                  self._selected = False
          
              def __repr__(self) :
                  return str(self)
          
              def __str__(self) :
                  return self.objSel <--- CAN ONLY RETURN A STRING AT THE TIME?
      

      Process 3: When changing the ComboBox value, change the axis value in list for check marked objects.
      Issue 3:  Need to have the values in the correct place and access it to make the change. Not sure how this would be done?

      Hopefully this is comprehensive, but please let me know if don't know what I'm talking about 🙂.

      Thank you in advance!

      Andre

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        On 13/04/2018 at 04:58, xxxxxxxx wrote:

        Hi Andre,

        we expect the issue rather in your implementation of the TreeViewFunctions. Maybe you can show us some code of these?

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          On 13/04/2018 at 05:31, xxxxxxxx wrote:

          Hi Andreas,

          Yeah sure! Let me know if you need anything else!

          # Global Variables
          PLUGIN_VERSION = 'v1.0'
          PLUGIN_ID = 1000010 #TESTING ID
          GRP_COMBOXFILES = 1002
          GRP_COMBOAXIS = 1003
          GRP_ADDBTN = 1004
          GRP_AUTOBTN = 1005
          GRP_RUNBTN = 1006
          OBJLIST = 1021
          STATUS = 1031
          INITIAL_WIDTH = 100
          INITIAL_HEIGHT = 20
          TREE_CHECK = 1
          TREE_OBJ = 2
          TREE_AXIS = 3
          TREE_FUNC = 4
          PATH = storage.GeGetStartupWritePath() + '/plugins/AO_Tools/eXpressoMachine/res/modules/'
          XNODESPATH = sys.path.append(storage.GeGetStartupWritePath() + '/plugins/AO_Tools/eXpressoMaker/res/modules')
          MAINBC = c4d.BaseContainer()
          ##################
            
          # Class which represent an object, aka an item in our list
          class PickObjs(object) :
            
              objSel = ""
              _selected = False
            
              def __init__(self, objSel) :
            
                  self.objSel = objSel
                  print self.objSel
            
              @property
              def IsSelected(self) :
                  return self._selected
            
              def Select(self) :
                  self._selected = True
            
              def Deselect(self) :
                  self._selected = False
            
              def __repr__(self) :
                  return str(self)
            
              def __str__(self) :
                  return self.objSel
            
            
          class ListView(c4d.gui.TreeViewFunctions) :
            
              def __init__(self) :
                  self.listOfObjs = list() # Store all objects we need to display in this list
                  
              def IsResizeColAllowed(self, root, userdata, lColID) :
                  return True
            
              def IsTristate(self, root, userdata) :
                  return False
                  
              def changeAxis(self, obj) :
                  print obj
                  
              # The user is allowed to move all columns.
              # TREEVIEW_MOVE_COLUMN must be set in the container of AddCustomGui.
              def IsMoveColAllowed(self, root, userdata, lColID) :
            
                  return False
                  
              # Return the first element in the hierarchy, or None if there is no element.
              def GetFirst(self, root, userdata) :
            
                  rValue = None if not self.listOfObjs else self.listOfObjs[0]
                  return rValue
                  
              # Return a child of a node, since we only want a list, we return None everytime
              def GetDown(self, root, userdata, obj) :
            
                  return None
                  
              # Returns the next Object to display after arg:'obj'
              def GetNext(self, root, userdata, obj) :
            
                  rValue = None
                  currentObjIndex = self.listOfObjs.index(obj)
                  nextIndex = currentObjIndex + 1
                  if nextIndex < len(self.listOfObjs) :
                      rValue = self.listOfObjs[nextIndex]
            
                  return rValue
                  
              # Returns the previous Object to display before arg:'obj'
              def GetPred(self, root, userdata, obj) :
            
                  rValue = None
                  currentObjIndex = self.listOfObjs.index(obj)
                  predIndex = currentObjIndex - 1
                  if 0 <= predIndex < len(self.listOfObjs) :
                      rValue = self.listOfObjs[predIndex]
            
                  return rValue
                  
              # Return a unique ID for the element in the TreeView.
              def GetId(self, root, userdata, obj) :
            
                  return hash(obj)
                  
              # Called when the user selects an element.
              def Select(self, root, userdata, obj, mode) :
            
                  if mode == c4d.SELECTION_NEW:
                      for tex in self.listOfObjs:
                          tex.Deselect()
                      obj.Select()
                  elif mode == c4d.SELECTION_ADD:
                      obj.Select()
                  elif mode == c4d.SELECTION_SUB:
                      obj.Deselect()
            
              def IsSelected(self, root, userdata, obj) :
                  """
                  Returns: True if *obj* is selected, False if not.
                  """
                  return obj.IsSelected
                  
              # Called when the user clicks on a checkbox for an object in a c4d.LV_CHECKBOX` column.
              def SetCheck(self, root, userdata, obj, column, checked, msg) :
            
                  if checked:
                  
                      obj.Select()
                      
                  else:
                  
                      obj.Deselect()
                      
              # Returns: (int) : Status of the checkbox in the specified *column* for *obj*.
              def IsChecked(self, root, userdata, obj, column) :
            
                  if obj.IsSelected:
              
                      return c4d.LV_CHECKBOX_CHECKED | c4d.LV_CHECKBOX_ENABLED
                      
                  else:
                  
                      return c4d.LV_CHECKBOX_ENABLED
                      
              # Returns the name to display for arg:'obj', only called for column of type LV_TREE
              def GetName(self, root, userdata, obj) :
            
                  return str(obj)
                  
              # Create all context menu values (Mouse Right Click)
              def CreateContextMenu(self, root, userdata, obj, lColumn, bc) :
                  
                  bc.RemoveData(900001) # Remove all option
              
              # Draw into a Cell, only called for column of type LV_USER
              def DrawCell(self, root, userdata, obj, col, drawinfo, bgColor) :
            
                  if col == TREE_OBJ:
                  
                      name = obj.GetName()
                      geUserArea = drawinfo["frame"]
                      w = geUserArea.DrawGetTextWidth(name)
                      h = geUserArea.DrawGetFontHeight()
                      xpos = drawinfo["xpos"]
                      ypos = drawinfo["ypos"] + drawinfo["height"]
                      drawinfo["frame"].DrawText(name, xpos, ypos - h * 1.1)
                      
                  elif col == TREE_AXIS:
                  
                      name = obj.GetName()
                      geUserArea = drawinfo["frame"]
                      w = geUserArea.DrawGetTextWidth(name)
                      h = geUserArea.DrawGetFontHeight()
                      xpos = drawinfo["xpos"]
                      ypos = drawinfo["ypos"] + drawinfo["height"]
                      drawinfo["frame"].DrawText(name, xpos, ypos - h * 1.1)
                  
                  elif col == TREE_FUNC:
                  
                      name = obj.GetName()
                      geUserArea = drawinfo["frame"]
                      w = geUserArea.DrawGetTextWidth(name)
                      h = geUserArea.DrawGetFontHeight()
                      xpos = drawinfo["xpos"]
                      ypos = drawinfo["ypos"] + drawinfo["height"]
                      drawinfo["frame"].DrawText(name, xpos, ypos - h * 1.1)
                      
              # Called when a delete event is received.
              def DeletePressed(self, root, userdata) :
            
                  for obj in reversed(self.listOfObjs) :
                  
                      if obj.IsSelected:
                      
                          self.listOfObjs.remove(obj)
                                          
          # Main class for the plugin dialog (UI).
          class eXpressoMakerDialog(gui.GeDialog) :
            
              _treegui = None # Our CustomGui TreeView
              _listView = ListView() # Our Instance of c4d.gui.TreeViewFunctions
              
              # Create the dialog's layout
              def CreateLayout(self) :
              
                  self.SetTitle('eXpresso Machine ' + PLUGIN_VERSION) # Title name
            
                  ################### Main group container for all the widgets.
                  self.GroupBegin(10000, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, 1, 1, 'MainGroup')
                  
                  ################ Combo box that gets the sub-modules from the modules folder.
                  self.GroupBegin(10001, c4d.BFH_SCALEFIT, 1, 1, 'Function')
                  self.GroupBorder(c4d.BORDER_GROUP_OUT)
                  self.GroupBorderSpace(10, 10, 10, 10)
                  self.AddComboBox(GRP_COMBOXFILES, c4d.BFH_SCALEFIT, INITIAL_WIDTH, INITIAL_HEIGHT)
                  
                  # Get all the modules in list and add it as a child of the combo box.
                  filesSubID = 0
                  
                  for file in listFiles() :
                      self.AddChild(GRP_COMBOXFILES, filesSubID, file)
                      filesSubID += 1
            
                  self.GroupEnd()
                  ################
                  
                  ################ Selection group container.
                  self.GroupBegin(10002, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, 2, 1, 'Selection')
                  self.GroupBorder(c4d.BORDER_GROUP_OUT)
                  self.GroupBorderSpace(10, 10, 10, 10)
                  
                  ############# Main menu buttons group container.
                  self.GroupBegin(10020, c4d.BFV_SCALEFIT, 1, 1, 'Menu')
                  
                  ########## Axis layout group container, combo box and button.
                  self.GroupBegin(10021, c4d.BFH_SCALEFIT, 1, 1, 'Axis')
                  self.GroupBorder(c4d.BORDER_GROUP_OUT)
                  self.GroupBorderSpace(10, 10, 10, 10)
                  self.AddComboBox(GRP_COMBOAXIS, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, 30, INITIAL_HEIGHT)     
            
                  # Get all the axis in list and add it as a child of the combo box.
                  axisID = 0
                  global axisList
                  axisList = ['X', 'Y', 'Z']
                  
                  for axis in axisList:
                      self.AddChild(GRP_COMBOAXIS, axisID, axis)
                      axisID += 1
                      
                  self.GroupEnd()    
                  ##########
                  
                  ########## Objects layout group container and function buttons.
                  self.GroupBegin(10022, c4d.BFH_SCALEFIT, 1, 1, 'Objects')
                  self.GroupBorder(c4d.BORDER_GROUP_OUT)
                  self.GroupBorderSpace(10, 10, 10, 10)
                  self.AddButton(GRP_AUTOBTN, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, INITIAL_WIDTH, INITIAL_HEIGHT, 'Auto-Find')
                  self.AddButton(GRP_ADDBTN, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, INITIAL_WIDTH, INITIAL_HEIGHT, 'Add')
                  self.GroupEnd()
                  ##########
                  
                  self.GroupEnd()
                  #############
                  
                  ############# Object TreeView container, where list of object, axis and function selection will be displayed. Each line is selectable and mutable.
                  self.GroupBegin(10023, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, 1, 1, 'Object List')
                  
                  treeViewGUI = c4d.BaseContainer()
                  treeViewGUI.SetBool(c4d.TREEVIEW_BORDER, c4d.BORDER_THIN_IN)
                  treeViewGUI.SetBool(c4d.TREEVIEW_BORDER, True)
                  treeViewGUI.SetBool(c4d.TREEVIEW_HAS_HEADER, True)
                  treeViewGUI.SetBool(c4d.TREEVIEW_HIDE_LINES, True)
                  treeViewGUI.SetBool(c4d.TREEVIEW_MOVE_COLUMN, True)
                  treeViewGUI.SetBool(c4d.TREEVIEW_RESIZE_HEADER, True)
                  treeViewGUI.SetBool(c4d.TREEVIEW_FIXED_LAYOUT, True)
                  treeViewGUI.SetBool(c4d.TREEVIEW_ALTERNATE_BG, True)
            
                  self._treegui = self.AddCustomGui(OBJLIST, c4d.CUSTOMGUI_TREEVIEW, "", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 400, 0, treeViewGUI)
                  self.GroupEnd()
                  #############
                  
                  self.GroupEnd()
                  ################
                  
                  ################ Status group container, where informs the user about the function actions.
                  self.GroupBegin(10003, c4d.BFH_SCALEFIT, 1, 1)
                  self.AddStaticText(STATUS, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT)
                  self.GroupEnd()
                  ################
                  
                  ################ Run group container that includes the main button to run all of the list functions.
                  self.GroupBegin(10004, c4d.BFH_SCALEFIT, 1, 1)
                  self.AddSeparatorV(INITIAL_WIDTH, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT)        
                  self.AddButton(GRP_RUNBTN, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, INITIAL_WIDTH, INITIAL_HEIGHT, 'Run')
                  self.GroupEnd()
                  ################
            
                  self.GroupEnd()
                  ###################
                  
                  return True
                  
              # Initialize default values
              def InitValues(self) :
              
                  # Initialize the column layout for the TreeView.
                  layout = c4d.BaseContainer()
                  layout.SetLong(TREE_CHECK, c4d.LV_CHECKBOX)
                  layout.SetLong(TREE_OBJ, c4d.LV_TREE)
                  layout.SetLong(TREE_AXIS, c4d.LV_USER)
                  layout.SetLong(TREE_FUNC, c4d.LV_USER)
                  self._treegui.SetLayout(TREE_FUNC, layout)
            
                  # Set the header titles.
                  self._treegui.SetHeaderText(TREE_CHECK, "")
                  self._treegui.SetHeaderText(TREE_OBJ, "Object")
                  self._treegui.SetHeaderText(TREE_AXIS, "Axis")
                  self._treegui.SetHeaderText(TREE_FUNC, "Function")
                  self._treegui.Refresh()
            
                  # Set TreeViewFunctions instance used by our CUSTOMGUI_TREEVIEW
                  self._treegui.SetRoot(self._treegui, self._listView, None)
                  return True
                          
               # Iterate through all the scene objects that include the words 'PIVOT' and 'MOVE' and append it to a list.
              def getObjs(self, op, output) : 
                  
                  while op:
                  
                      if 'PIVOT' in op.GetName().upper() or 'MOVE' in op.GetName().upper() :
                                           
                          output.append(op)
                              
                      self.getObjs(op.GetDown(),output)
                      op = op.GetNext()
                      
                  return output
              
              # Return the correct ID for the axis selected.
              def getAxis(self, axis) :
              
                  selAxis = {'X' : 'c4d.VECTOR_X', # ID: 1000
                          'Y' : 'c4d.VECTOR_Y', # ID: 1001
                          'Z' : 'c4d.VECTOR_Z'} # ID: 1002
                          
                  return selAxis[axis]
                  
              '''NOT USED 
              def CoreMessage(self, id, msg) :
                     
                  return gui.GeDialog.CoreMessage(self, id, msg)
                  '''
                  
              # Built-In function to run events when triggered by the dialog widgets.
              def Command(self, id, msg) :
              
                  fileSelectedIndex = self.GetInt32(GRP_COMBOXFILES) # Get the function combo box index for the value selected.
                  axisSelectedIndex = self.GetInt32(GRP_COMBOAXIS) # Get the axis combo box index for the value selected.
                  
                  doc = c4d.documents.GetActiveDocument() # Get active document.
                  
                  # Event trigger for the axis combo box and button.
                  if (id == GRP_COMBOAXIS) :
            
                      if self._listView.listOfObjs != []:
                          i = 0
                          for obj in self._listView.listOfObjs:
            
                              print self._listView.changeAxis(obj)
                          
                          self.SetString(STATUS, 'Axis changed!') # Event run, show the event message to the user.
                          
                      else:
                      
                          self.SetString(STATUS, 'No objects to change the axis!') # If no objects are on list, show the event message to the user.
                          
                  # Event trigger for the add button.
                  if (id == GRP_ADDBTN) :
            
                      selObjs = doc.GetActiveObjects(0) # Get a list of selected objects.
                                  
                      if selObjs != []:
                      
                          # Add data to our DataStructure (ListView)
                          for obj in selObjs:
                              newID = len(self._listView.listOfObjs) + 1 
                              objName = obj.GetName()
                              axisName = axisList[axisSelectedIndex].upper()
                              funcName = str(files[fileSelectedIndex])
                              
                              self._listView.listOfObjs.append([objName, axisName, funcName])
                              for objSel in self._listView.listOfObjs:
                              
                                  for value in objSel:
                                  
                                      PickObjs(value)
                              
                          # Refresh the TreeView
                          self._treegui.Refresh()
                          
                          self.SetString(STATUS, 'Object(s) added!') # Event run, show the event message to the user.
                          
                      else:
            
                          self.SetString(STATUS, 'No objects selected!') # If no objects are on list, show the event message to the user.
                         
                  if (id == GRP_AUTOBTN) :
                  
                      parentObjs = doc.GetObjects() # Get a list of all parent objects of the scene.
                      selObjs = []
                      
                      if parentObjs != []:
                          
                          # Get all the objects that have the word 'PIVOT' or 'MOVE' on its name.
                          # Case sensitivity is not a a problem, as the function converts the name to upper case.
                          self.getObjs(parentObjs[0], selObjs)
                          
                          if selObjs != []:
                          
                              # Add data to our DataStructure (ListView)
                              for obj in selObjs:
                                  newID = len(self._listView.listOfObjs) + 1 
                                  objName = PickObjs(obj.GetName(), axisList[axisSelectedIndex].upper(), str(files[fileSelectedIndex]))
                                  self._listView.listOfObjs.append(objName)
                                  
                              # Refresh the TreeView
                              self._treegui.Refresh()
                              
                              self.SetString(STATUS, 'Object(s) Added') # Event run, show the event message to the user.
                              
                          else:
                          
                              self.SetString(STATUS, 'Could not find any objects!') # If no objects are on list, show the event message to the user.
                          
                      else:
                  
                          self.SetString(STATUS, 'Could not find any objects!') # If no objects are on list, show the event message to the user.
                          
                  if (id == GRP_COMBOXFILES) :
                  
                      prevMsg = self.GetString(OBJLIST) # Get the list (message) from the multi-line widget.
            
                      if prevMsg != '':       
                  
                          self.SetString(STATUS, 'Function changed to ' + str(files[fileSelectedIndex])) # Event run, show the event message to the user.
                      
                      else:
                      
                          self.SetString(STATUS, 'No objects selected!') # If no objects are on list, show the event message to the user.
                          
                  if (id == GRP_RUNBTN) :
                  
                      prevMsg = self.GetString(OBJLIST) # Get the list (message) from the multi-line widget.
            
                      if prevMsg != '':
                  
                          with localimport('res/modules') :
                          
                              lines = prevMsg.split('\n') # Split the line by the new line character into different sections.
                              del lines[-1] # Delete the last empty line.
                              lineIndex = 0
            
                              for line in lines:
                              
                                  wordList = line.split() # Split the line into different sections.
                                  
                                  # Freeze the transformations for of the object.
                                  for id, value in MAINBC:
                                      
                                      if id == lineIndex:
            
                                           objBC = MAINBC.GetData(id)
                                           
                                           for id, value in objBC:
                                              print id, value
                                  
                                  if wordList[-1] not in sys.modules:
                                  
                                      __import__(wordList[-1]) # Call the correct model to run.
                                      
                                  else:
                                  
                                      reload(__import__(wordList[-1])) # If the module modified, reload the model and run it.
                                      
                                  lineIndex += 1
                                  
                              self.SetString(STATUS, 'Rig done!') # Event run, show the event message to the user.
                              
                      else:
                      
                          self.SetString(STATUS, 'No objects selected!') # If no objects are on list, show the event message to the user.
            
                  return True
              
          # Return the relevant list of objects that contain the file extension '.py'
          # and do not start with the file name '__innit__'
          def listFiles() :
            
              global files
              files = []
            
              if os.path.exists(PATH) :
            
                  for file in os.listdir(PATH) :
                  
                      if file.endswith('.py') and os.path.splitext(file)[0] != '__init__':
                  
                          files.append(os.path.splitext(file)[0])
              
              return files
              
          # Open the plugin in a new window when the main plugin function is called
          class eXpressoMakerPlugin(plugins.CommandData) :
            
              dialog = None
              
              # Creates the dialog
              def Execute(self, doc) :
              
                  if self.dialog is None:
                      self.dialog = eXpressoMakerDialog()
                   
                  return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, defaultw=300, defaulth=150, xpos=-1, ypos=-1)
              
              # Manages the dialog
              def RestoreLayout(self, sec_ref) :
            
                  if self.dialog is None:
                      self.dialog = eXpressoMakerDialog()
                   
                  return self.dialog.Restore(PLUGIN_ID, secret=sec_ref)
                  
          if __name__ == '__main__':
            
              path, fn = os.path.split(__file__)
              bmp = bitmaps.BaseBitmap() # We need an instance of BaseBitmap class to use an image
              bmp.InitWith(os.path.join(path, 'res/icons/', 'icon.tif')) # The location where the menu image exists
               
              okyn = plugins.RegisterCommandPlugin(PLUGIN_ID, 'eXpresso Machine ' + PLUGIN_VERSION, 0, bmp, 'eXpresso Machine ' + PLUGIN_VERSION, eXpressoMakerPlugin())
              
              if (okyn) :
                  print 'eXpresso Machine ' + PLUGIN_VERSION + ' Loaded!'
                  c4d.StatusSetText('eXpresso Machine ' + PLUGIN_VERSION + ' Loaded!')
          

          Thank you very much Andreas! 🙂

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            On 18/04/2018 at 09:23, xxxxxxxx wrote:

            Hi Andre,

            terribly sorry, I need to ask for a bit more patience. I'll get back to you as soon as possible. Hopefully still this week.

            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              On 19/04/2018 at 00:51, xxxxxxxx wrote:

              Hi Andreas,

              No need to apologise! I appreciate your help! 🙂

              Thank you very much again!

              1 Reply Last reply Reply Quote 0
              • H Offline
                Helper
                last edited by

                On 20/04/2018 at 06:07, xxxxxxxx wrote:

                Hi Andre,

                I think, the main problem of your code is, that you are actually storing tuples in the tree content list, not "PickObjs" (as all the rest of your code assumes). This causes all kinds of problems all over the place. This you will need to either debug yourself or ask someone in our community for help.

                This is also the reason, why you get the entire tuple shown in the first column.

                GetName() delivers only the content of the LV_TREE column (basically the main column).
                All LV_USER columns you need to draw yourself in DrawCell(). Which again doesn't work in your code, because the tuples stored in the list have no GetName() function. Also DrawCell() needs to draw only the LV_USER columns, no need to take care of TREE_OBJ in there.

                One general advice:
                Pay attention to any errors on the Console. These can usually get you already a long way.

                I hope, this helps to get you started.

                1 Reply Last reply Reply Quote 0
                • H Offline
                  Helper
                  last edited by

                  On 23/04/2018 at 05:55, xxxxxxxx wrote:

                  Hi Andreas,

                  Thank you immensely for your help!

                  I've managed to correct the code and make it do what I wanted, with your advice, but (apologies if I didn't understand) how can I access the the data for each "cell"? I will get the LV_TREE obj but not the LV_USER data.

                  I understand that the list is only appending the LV_TREE obj and not the other two, because it is returned by the function.
                  My question would be how to attach the other LV_USER values to the same list, so I can use it in a later stage?
                  If this is not possible, should I create a new list/baseContainer?

                  Thank you so much!

                  Andre

                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    Helper
                    last edited by

                    On 23/04/2018 at 08:12, xxxxxxxx wrote:

                    Hi Andre,

                    I'm not sure I understand your question. if I fail to answer your question, please don't hesitate to ask again.

                    You need to differentiate two things. One is your data (i.e. a linked list of objects or an array of your PickObjects) and the other is the display in the TreeView.

                    The tree doesn't care for your data, but instead you need to tell it, what to display in the LV_TREE column (via GetName()) and for all other columns (via DrawCell()). In either function you get the obj parameter, which from the tree point of view is just an opaque reference (it's not used inside by the tree), which provides you with the means to pick whatever needed from your data.

                    Or to answer your question "how can I access the the data for each cell?" more directly: You don't. The tree does not store any data, it just displays your data.

                    Similar in the other direction. For example on left click onto the Axis column, you want to have a popup with axis options. Well, you again get the obj reference in MouseDown(). Then you can for example use ShowPopupDialog() and with the result you'd update your data or the entities referred to by your data. Of course you could achieve similar by using the tree's context menu directly (CreateContextMenu()).

                    Unfortunately here's also a small limitation of the Python API. The C++ API has PopupEditText(), which would allow for overlay text editing, roughly as shown in your screenshot, but that's currently missing in the Python API.

                    1 Reply Last reply Reply Quote 0
                    • H Offline
                      Helper
                      last edited by

                      On 24/04/2018 at 01:06, xxxxxxxx wrote:

                      Hi Andreas,

                      You did answer it and you also gave me some alternative and ideas to use.
                      Thank you so much! It makes more sense, now.
                      I'm still getting the grips with Python, but it seems that C++ is the way to go as well.

                      Appreciate your patience and help! 🙂

                      Have a great day!

                      Andre

                      1 Reply Last reply Reply Quote 0
                      • First post
                        Last post