Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware 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

    TreeView rows selected?

    Cinema 4D SDK
    2024 python
    2
    4
    261
    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.
    • chuanzhenC
      chuanzhen
      last edited by chuanzhen

      hi,
      why are all rows highlighted(Although the selection of the function was correct, the text display color of the entire tree view has been changed) when selecting a row in the TreeView using the c4d.LV_USER parameter in each column (as shown in the left figure), and why is only that row highlighted when selecting a row in the first column using the c4d.LV_TREE parameter (as shown in the right figure)?

      how it can be done so that when all columns use c4d.LV_USER, the selected row can be activated as shown in the right figure
      26e5f6dc-454c-4989-a438-e8804e03f841-image.png

      Thanks for any help!

      code:

      import c4d
      import random
      from c4d import gui
      # Welcome to the world of Python
      
      NAME = 0
      LINKTO = 1
      LINK = 2
      TYPE = 3
      
      
      
      class TreeView_Item(object):
      
          def __init__(self,):
      
              self.type = 'psr'    
              self.selected = False  
      
      
              self.obj_name = str(random.randint(1,100))  
      
              self.linkto_name = ""  
      
      
      
          @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.obj_name
      
      
      class TreeView(c4d.gui.TreeViewFunctions):
      
          def __init__(self,items_list=None):
      
              self.items_list = items_list if items_list else []
          def GetLineHeight(self,root, userdata, obj, col, area):
      
              return area.DrawGetFontHeight()
      
          def IsResizeColAllowed(self, root, userdata, lColID):
              return True
      
          def IsTristate(self, root, userdata):
              return False
      
          def GetColumnWidth(self, root, userdata, obj, col, area):
              """Measures the width of cells.
      
              Although this function is called #GetColumnWidth and has a #col, it is
              not only executed by column but by cell. So, when there is a column
              with items requiring the width 5, 10, and 15, then there is no need
              for evaluating all items. Each item can return its ideal width and
              Cinema 4D will then pick the largest value.
      
              Args:
                  root (any): The root node of the tree view.
                  userdata (any): The user data of the tree view.
                  obj (any): The item for the current cell.
                  col (int): The index of the column #obj is contained in.
                  area (GeUserArea): An already initialized GeUserArea to measure
                   the width of strings.
      
              Returns:
                  TYPE: Description
              """
              # The default width of a column is 80 units.
              width = 80
              # Replace the width with the text width. area is a prepopulated
              # user area which has already setup all the font stuff, we can
              # measure right away.
      
              if col == NAME:
                  return area.DrawGetTextWidth(obj.obj_name) + 5
              if col == LINKTO:
                  return area.DrawGetTextWidth("-->") + 5
              if col == LINK:
                  return area.DrawGetTextWidth(obj.linkto_name) + 5
      
              if col == TYPE:
                  return area.DrawGetTextWidth(obj.type) + 5
      
              return width
      
      
          def GetFirst(self, root, userdata):
              """
              Return the first element in the hierarchy, or None if there is no element.
              """
              rValue = None if not len(self.items_list) else self.items_list[0]
              return rValue
      
      
          def GetNext(self, root, userdata, obj):
              """
              Returns the next Object to display after arg:'obj'
              """
              rValue = None
              currentObjIndex = self.items_list.index(obj)
              nextIndex = currentObjIndex + 1
              if nextIndex < len(self.items_list):
                  rValue = self.items_list[nextIndex]
      
              return rValue
      
          def GetPred(self, root, userdata, obj):
              """
              Returns the previous Object to display before arg:'obj'
              """
              rValue = None
              currentObjIndex = self.items_list.index(obj)
              predIndex = currentObjIndex - 1
              if 0 <= predIndex < len(self.items_list):
                  rValue = self.items_list[predIndex]
      
              return rValue
      
          def GetId(self, root, userdata, obj):
              """
              Return a unique ID for the element in the TreeView.
              """
              return hash(obj)
      
      
          def Select(self, root, userdata, obj, mode):
      
              print(obj.obj_name)
              if mode == c4d.SELECTION_NEW:
                  for item in self.items_list:
                      item.Deselect()
                  obj.Select()
              elif mode == c4d.SELECTION_ADD:
                  obj.Select()
              elif mode == c4d.SELECTION_SUB:
                  obj.Deselect()
      
          def IsSelected(self, root, userdata, obj):
      
              return obj.IsSelected
      
          def DeletePressed(self, root, userdata):
              "Called when a delete event is received."
              for item in reversed(self.items_list):
                  if item.IsSelected:
                      self.items_list.remove(item)
      
          def GetName(self, root, userdata, obj):
              """
              Returns the name to display for arg:'obj', only called for column of type LV_TREE
              """
              return str(obj)  # Or obj.texturePath
      
          def DrawCell(self, root, userdata, obj, col, drawinfo, bgColor):
              """
              Draw into a Cell, only called for column of type LV_USER
              """
              if col == NAME:
                  text = obj.obj_name
      
              elif col == LINKTO:
                  text = '-->'
              elif col == LINK:
                  text = obj.linkto_name
              elif col == TYPE:
                  text = obj.type
              else:
                  text = ''
      
              canvas = drawinfo["frame"]
      
              xpos = drawinfo["xpos"]
              ypos = drawinfo["ypos"]
      
      
              canvas.DrawText(text, xpos, ypos)
      
      
          def DoubleClick(self, root, userdata, obj, col, mouseinfo):
      
              return True
      
      
      class test_dialog(gui.GeDialog):
          def __init__(self):
              self._treegui = None
              self.treeview = TreeView()
          def CreateLayout(self):
              # Other than edit fields, buttons do not have a builtin bubble help.
              customgui = c4d.BaseContainer()
              customgui.SetBool(c4d.TREEVIEW_BORDER, c4d.BORDER_THIN_IN)
              customgui.SetBool(c4d.TREEVIEW_HAS_HEADER, True)  # True if the tree view may have a header line.
              customgui.SetBool(c4d.TREEVIEW_HIDE_LINES, False)  # True if no lines should be drawn.
              customgui.SetBool(c4d.TREEVIEW_MOVE_COLUMN, False)  # True if the user can move the columns.
              customgui.SetBool(c4d.TREEVIEW_RESIZE_HEADER, True)  # True if the column width can be changed by the user.
              customgui.SetBool(c4d.TREEVIEW_FIXED_LAYOUT, True)  # True if all lines have the same height.
              customgui.SetBool(c4d.TREEVIEW_ALTERNATE_BG, True)  # Alternate background per line.
              customgui.SetBool(c4d.TREEVIEW_CURSORKEYS, True)  # True if cursor keys should be processed.
              customgui.SetBool(c4d.TREEVIEW_NOENTERRENAME, True)  # Suppresses the rename popup when the user presses enter.
              customgui.SetBool(c4d.TREEVIEW_NO_MULTISELECT, False) 
              self._treegui = self.AddCustomGui(1000, c4d.CUSTOMGUI_TREEVIEW, "", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 300,
                                                300, customgui)
              if not self._treegui:
                  print("[ERROR]: Could not create TreeView")
                  return False
      
              self.AddButton(1001, c4d.BFH_CENTER, name="Add")
      
              return True
      
      
          def InitValues(self) -> bool:
              layout = c4d.BaseContainer()
              layout.SetInt32(NAME, c4d.LV_USER)
              layout.SetInt32(LINKTO, c4d.LV_USER)
              layout.SetInt32(LINK, c4d.LV_USER)
              layout.SetInt32(TYPE, c4d.LV_USER)
      
              self.layout = layout
              self._treegui.SetLayout(4, layout)
      
              # Set the header titles.
              self._treegui.SetHeaderText(NAME, "Name")
              self._treegui.SetHeaderText(LINKTO, "")
              self._treegui.SetHeaderText(LINK, "Link")
              self._treegui.SetHeaderText(TYPE, "Type")
      
      
              # Set TreeViewFunctions instance used by our CUSTOMGUI_TREEVIEW
              self._treegui.SetRoot(self._treegui, self.treeview, None)
              self._treegui.Refresh()
              return True
      
          def Command(self, id, msg):
              if id == 1001:
                  item = TreeView_Item()
                  self.treeview.items_list.append(item)
                  self._treegui.Refresh()
                  return True
              return True
      
      
      # Execute main()
      if __name__=='__main__':
      
      
          dlg = test_dialog()
      
          dlg.Open(c4d.DLG_TYPE_ASYNC,0 -1,-1,400,400)
      
      1 Reply Last reply Reply Quote 0
      • chuanzhenC
        chuanzhen
        last edited by

        This post is deleted!
        1 Reply Last reply Reply Quote 0
        • M
          m_adam
          last edited by m_adam

          Hi @chuanzhen the fact that the first time (when nothing is selected) correctly respect the COLOR_TEXT is kind of a bug for treeview containing only LV_USER.

          When you are using LV_USER the DrawCell method is called and you are responsible to define the color of your text via DrawSetTextCol. But if you do not set any text color, the GeUserArea will use the previously defined color. Which is in this case COLOR_TEXT when nothing is selected. Then when you select something, the last call of this DrawSetTextCol internally done by Cinema 4D define it to "white" color so that's why all texts are white. Then when there is one column that is defined as LV_TREE it will then call DrawSetTextCol with the correct color (COLOR_TEXT or COLOR_TEXT_SELECTED) and therefor your call DrawText will use this color.

          So with that's said, do not forget to manage your color in your DrawCell method something like that:

          txtColorDict = canvas.GetColorRGB(c4d.COLOR_TEXT_SELECTED) if obj.IsSelected else canvas.GetColorRGB(c4d.COLOR_TEXT)
          txtColorVector = c4d.Vector(txtColorDict["r"]/255.0, txtColorDict["g"]/255.0, txtColorDict["b"]/255.0)
          canvas.DrawSetTextCol(txtColorVector, bgColor)
          canvas.DrawText(text, xpos, ypos)
          

          Cheers,
          Maxime.

          MAXON SDK Specialist

          Development Blog, MAXON Registered Developer

          chuanzhenC 1 Reply Last reply Reply Quote 0
          • chuanzhenC
            chuanzhen @m_adam
            last edited by

            @m_adam Thanks,it works well👍
            2b524b98-f131-4d69-bcf0-4dec858821ab-image.png

            this is code:

            import c4d
            import random
            from c4d import gui
            # Welcome to the world of Python
            
            NAME = 0
            LINKTO = 1
            LINK = 2
            TYPE = 3
            
            
            class TreeView_Item(object):
            
                def __init__(self,):
            
                    self.type = 'psr'   
                    self.selected = False  
            
            
                    self.obj_name = str(random.randint(1,100)) 
            
                    self.linkto_name = "" 
            
            
            
                @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.obj_name
            
            
            class TreeView(c4d.gui.TreeViewFunctions):
            
                def __init__(self,items_list=None):
            
                    self.items_list = items_list if items_list else []
                def GetLineHeight(self,root, userdata, obj, col, area):
            
                    return area.DrawGetFontHeight()
            
                def IsResizeColAllowed(self, root, userdata, lColID):
                    return True
            
                def IsTristate(self, root, userdata):
                    return False
            
                def GetColumnWidth(self, root, userdata, obj, col, area):
                    """Measures the width of cells.
            
                    Although this function is called #GetColumnWidth and has a #col, it is
                    not only executed by column but by cell. So, when there is a column
                    with items requiring the width 5, 10, and 15, then there is no need
                    for evaluating all items. Each item can return its ideal width and
                    Cinema 4D will then pick the largest value.
            
                    Args:
                        root (any): The root node of the tree view.
                        userdata (any): The user data of the tree view.
                        obj (any): The item for the current cell.
                        col (int): The index of the column #obj is contained in.
                        area (GeUserArea): An already initialized GeUserArea to measure
                         the width of strings.
            
                    Returns:
                        TYPE: Description
                    """
                    # The default width of a column is 80 units.
                    width = 80
                    # Replace the width with the text width. area is a prepopulated
                    # user area which has already setup all the font stuff, we can
                    # measure right away.
            
                    if col == NAME:
                        return area.DrawGetTextWidth(obj.obj_name) + 5
                    if col == LINKTO:
                        return area.DrawGetTextWidth("-->") + 5
                    if col == LINK:
                        return area.DrawGetTextWidth(obj.linkto_name) + 5
            
                    if col == TYPE:
                        return area.DrawGetTextWidth(obj.type) + 5
            
                    return width
            
            
                def GetFirst(self, root, userdata):
                    """
                    Return the first element in the hierarchy, or None if there is no element.
                    """
                    rValue = None if not len(self.items_list) else self.items_list[0]
                    return rValue
            
            
                def GetNext(self, root, userdata, obj):
                    """
                    Returns the next Object to display after arg:'obj'
                    """
                    rValue = None
                    currentObjIndex = self.items_list.index(obj)
                    nextIndex = currentObjIndex + 1
                    if nextIndex < len(self.items_list):
                        rValue = self.items_list[nextIndex]
            
                    return rValue
            
                def GetPred(self, root, userdata, obj):
                    """
                    Returns the previous Object to display before arg:'obj'
                    """
                    rValue = None
                    currentObjIndex = self.items_list.index(obj)
                    predIndex = currentObjIndex - 1
                    if 0 <= predIndex < len(self.items_list):
                        rValue = self.items_list[predIndex]
            
                    return rValue
            
                def GetId(self, root, userdata, obj):
                    """
                    Return a unique ID for the element in the TreeView.
                    """
                    return hash(obj)
            
            
                def Select(self, root, userdata, obj, mode):
            
                    print(obj.obj_name)
                    if mode == c4d.SELECTION_NEW:
                        for item in self.items_list:
                            item.Deselect()
                        obj.Select()
                    elif mode == c4d.SELECTION_ADD:
                        obj.Select()
                    elif mode == c4d.SELECTION_SUB:
                        obj.Deselect()
            
                def IsSelected(self, root, userdata, obj):
            
                    return obj.IsSelected
            
                def DeletePressed(self, root, userdata):
                    "Called when a delete event is received."
                    for item in reversed(self.items_list):
                        if item.IsSelected:
                            self.items_list.remove(item)
            
                def GetName(self, root, userdata, obj):
                    """
                    Returns the name to display for arg:'obj', only called for column of type LV_TREE
                    """
                    return str(obj)  # Or obj.texturePath
            
                def DrawCell(self, root, userdata, obj, col, drawinfo, bgColor):
                    """
                    Draw into a Cell, only called for column of type LV_USER
                    """
                    if col == NAME:
                        text = obj.obj_name
            
                    elif col == LINKTO:
                        text = '-->'
                    elif col == LINK:
                        text = obj.linkto_name
                    elif col == TYPE:
                        text = obj.type
                    else:
                        text = ''
            
                    canvas = drawinfo["frame"]
            
                    xpos = drawinfo["xpos"]
                    ypos = drawinfo["ypos"]
            
                    txtColorDict = canvas.GetColorRGB(c4d.COLOR_TEXT_SELECTED) if obj.IsSelected else canvas.GetColorRGB(
                        c4d.COLOR_TEXT)
                    txtColorVector = c4d.Vector(txtColorDict["r"] / 255.0, txtColorDict["g"] / 255.0, txtColorDict["b"] / 255.0)
                    canvas.DrawSetTextCol(txtColorVector, bgColor)
                    canvas.DrawText(text, xpos, ypos)
            
            
            
                def DoubleClick(self, root, userdata, obj, col, mouseinfo):
            
                    return True
            
            
            class test_dialog(gui.GeDialog):
                def __init__(self):
                    self._treegui = None
                    self.treeview = TreeView()
                def CreateLayout(self):
                    # Other than edit fields, buttons do not have a builtin bubble help.
                    customgui = c4d.BaseContainer()
                    customgui.SetBool(c4d.TREEVIEW_BORDER, c4d.BORDER_THIN_IN)
                    customgui.SetBool(c4d.TREEVIEW_HAS_HEADER, True)  # True if the tree view may have a header line.
                    customgui.SetBool(c4d.TREEVIEW_HIDE_LINES, False)  # True if no lines should be drawn.
                    customgui.SetBool(c4d.TREEVIEW_MOVE_COLUMN, False)  # True if the user can move the columns.
                    customgui.SetBool(c4d.TREEVIEW_RESIZE_HEADER, True)  # True if the column width can be changed by the user.
                    customgui.SetBool(c4d.TREEVIEW_FIXED_LAYOUT, True)  # True if all lines have the same height.
                    customgui.SetBool(c4d.TREEVIEW_ALTERNATE_BG, True)  # Alternate background per line.
                    customgui.SetBool(c4d.TREEVIEW_CURSORKEYS, True)  # True if cursor keys should be processed.
                    customgui.SetBool(c4d.TREEVIEW_NOENTERRENAME, True)  # Suppresses the rename popup when the user presses enter.
                    customgui.SetBool(c4d.TREEVIEW_NO_MULTISELECT, False)  
            
                    self._treegui = self.AddCustomGui(1000, c4d.CUSTOMGUI_TREEVIEW, "", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 300,
                                                      300, customgui)
                    if not self._treegui:
                        print("[ERROR]: Could not create TreeView")
                        return False
            
                    self.AddButton(1001, c4d.BFH_CENTER, name="Add")
            
                    return True
            
            
                def InitValues(self) -> bool:
                    layout = c4d.BaseContainer()
                    layout.SetInt32(NAME, c4d.LV_USER)
                    layout.SetInt32(LINKTO, c4d.LV_USER)
                    layout.SetInt32(LINK, c4d.LV_USER)
                    layout.SetInt32(TYPE, c4d.LV_USER)
            
                    self.layout = layout
                    self._treegui.SetLayout(4, layout)
            
                    # Set the header titles.
                    self._treegui.SetHeaderText(NAME, "Name")
                    self._treegui.SetHeaderText(LINKTO, "")
                    self._treegui.SetHeaderText(LINK, "Link")
                    self._treegui.SetHeaderText(TYPE, "Type")
            
            
                    # Set TreeViewFunctions instance used by our CUSTOMGUI_TREEVIEW
                    self._treegui.SetRoot(self._treegui, self.treeview, None)
                    self._treegui.Refresh()
                    return True
            
                def Command(self, id, msg):
                    if id == 1001:
                        item = TreeView_Item()
                        self.treeview.items_list.append(item)
                        self._treegui.Refresh()
                        return True
                    return True
            
            
            # Execute main()
            if __name__=='__main__':
            
            
                dlg = test_dialog()
            
                dlg.Open(c4d.DLG_TYPE_ASYNC,0 -1,-1,400,400)
            
            1 Reply Last reply Reply Quote 0
            • First post
              Last post