Navigation

    • Register
    • Login
        No matches found
    • Search
    1. Home
    2. mogh
    3. Posts
    • Profile
    • More
      • Following
      • Followers
      • Topics
      • Posts
      • Best
      • Groups

    Posts made by mogh

    RE: Script Befehl

    https://developers.maxon.net/docs/Cinema4DPythonSDK/html/modules/c4d/C4DAtom/GeListNode/BaseList2D/BaseObject/index.html#BaseObject.GetEditorMode

    drag n drop the (red dot) into the (c4d) comandline would have get you on track

    https://developers.maxon.net/docs/Cinema4DPythonSDK/html/classic_resource/base_list/obase.html

    kind regards

    posted in Cinema 4D SDK •
    RE: How can I make a simple input form for my Python script?

    ... while the Team probalby will ask you to provide more context / detail ... have you looked at the sdk examples ?

    https://github.com/PluginCafe/cinema4d_py_sdk_extended/tree/master/scripts/03_application_development/gui/dialog

    kind regards

    posted in Cinema 4D SDK •
    RE: Wish / request: c4d.CallComand()

    @a_block where is the PM system ? I can't find anything here in the forum ...

    posted in General Talk •
    RE: Wish / request: c4d.CallComand()

    I did some rudimentary logging of just my slection + callcomand and I cannot see a "slow" execution. So @a_block might have a hunch that its the doc passing / filesize / undo accumulation ...

    and what makes the "exponetial" feeling even more is that the engineers put screws (small stuff) at the bottom of the tree

    I only import one file at a time ... so my file size shrinks because I "connect" objects ....

    Sorted by time logged to console (145 MB , 3.965.783 polys, 547 calls on Callcomand)
    2022-03-03-Window_000064.png <- not all calls

    anyway its late fresh mind tomorrow

    cheers mogh

    posted in General Talk •
    RE: Wish / request: c4d.CallComand()

    Thanks @ferdinand for you explanation. I understand the problems and the unlikelihood of this idea.

    On the topic anyway hence your recall my import data problem, Do you have an idea why huge imports are exponentially in behavior?
    I have to log some statistics but my suspicion is that even tho the polycount per objects to connect is similar the more objects are in the doc the slower the callcomand is.

    Could you take a peak at the code internally of Connect Objects + Delete ? or perhaps its the selection of objects ... anyway the behavior is from slow to fast as less objects to connect in the doc which feels weird ...

    def select_children(mother, childrenlist):
        mother.SetBit(c4d.BIT_ACTIVE)
        for child in childrenlist:
            child.SetBit(c4d.BIT_ACTIVE)
    
    c4d.CallCommand(16768, 16768) # Connect Objects + Delete
    

    cheers mogh

    posted in General Talk •
    RE: Invoke Parent Function inside / outside class (TreeView)

    🙇 👏 💃 😌 Thank You @ferdinand

    Access an Enclosing Entity from a Subordinate Entity, was the solution I was searching for hence I needed to alter the GeDialog from inside the TreeViewFunctions. This seems to be the only solution hence these checkboxes belong to the treeview ?!?

    Anyway its working and I am very happy 🙂

    User sets checkbox -> Sum is calculated -> button is activated.

    I updated the example code (and removed the now unnecessary button to prevent further confusion) with the desired behavior for future readers.

    kind regards
    mogh

    """
    Adapted from:
        https://plugincafe.maxon.net/topic/10654/14102_using-customgui-listview/2
    """
    import c4d
    import random
     
    # Be sure to use a unique ID obtained from http://www.plugincafe.com/.
    PLUGIN_ID = 1000010  # TEST ID ONLY
     
    # TreeView Column IDs.
    ID_CHECKBOX = 1
    ID_NAME = 2
    ID_OTHER = 3
    ID_LONGFILENAME = 4
    MY_BUTON = 5
    HOW_MANY = 6
    ID_FILESIZE = 7
    HOW_MANY_MB = 8
    MY_CALC = 9
    
    TREEVIEW = 99
    
    # A tuple of characters to select from (a-z).
    CHARACTERS = tuple( chr ( n) for n in range(97, 122))
    
    
    class TextureObject(object):
        """
        Class which represent a texture, aka an Item in our list
        """
        def __init__(self):
            self.texturePath = TextureObject.RandomString(5, 10)
            self.otherData = TextureObject.RandomString(5, 20)
            self.longfilename = "-"
            self._selected = False
            self.filesize = TextureObject.RandomNumber()
    
        @staticmethod
        def RandomString(minLength, maxLength):
            """Returns a string of random characters with a length between 
            #minLength and #maxLength.
    
            The characters are taken from the 97 (a) to 122 (z) ASCII range.
            """
            return "".join(
                (random.choice(CHARACTERS) for _ in range(minLength, maxLength)))
    
        @staticmethod
        def RandomNumber():
            return random.randrange(1, 99)
    
        @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.texturePath
     
     
    class ListView(c4d.gui.TreeViewFunctions):
     
        def __init__(self, host):
            """Initializes a ListView with a host.
    
            Args:
                host (c4d.gui.GeDialog): The hosting dialog.
            """
            # Add ten mock data texture objects.
            self.listOfTexture = [TextureObject() for _ in range(10)]
            if not isinstance(host, c4d.gui.GeDialog):
                raise TypeError("Expected {} for argument 'host'. Received: {}".format(c4d.gui.GeDialog, host))
            else:
                self._host = host
    
        def DoSomethingWithDialog(self):
            """Calls the dialog over the stored reference.
            """
            self._host.calc_selected()
    
        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 == ID_NAME:
                return area.DrawGetTextWidth(obj.texturePath) + 5
            if col == ID_OTHER:
                return area.DrawGetTextWidth(obj.otherData) + 5
            if col == ID_LONGFILENAME:
                return area.DrawGetTextWidth(obj.longfilename) + 5
                
            return width
    
        def IsMoveColAllowed(self, root, userdata, lColID):
            # The user is allowed to move all columns.
            # TREEVIEW_MOVE_COLUMN must be set in the container of AddCustomGui.
            return True
     
        def GetFirst(self, root, userdata):
            """
            Return the first element in the hierarchy, or None if there is no element.
            """
            rValue = None if not self.listOfTexture else self.listOfTexture[0]
            return rValue
     
        def GetDown(self, root, userdata, obj):
            """
            Return a child of a node, since we only want a list, we return None everytime
            """
            return None
     
        def GetNext(self, root, userdata, obj):
            """
            Returns the next Object to display after arg:'obj'
            """
            rValue = None
            currentObjIndex = self.listOfTexture.index(obj)
            nextIndex = currentObjIndex + 1
            if nextIndex < len(self.listOfTexture):
                rValue = self.listOfTexture[nextIndex]
     
            return rValue
     
        def GetPred(self, root, userdata, obj):
            """
            Returns the previous Object to display before arg:'obj'
            """
            rValue = None
            currentObjIndex = self.listOfTexture.index(obj)
            predIndex = currentObjIndex - 1
            if 0 <= predIndex < len(self.listOfTexture):
                rValue = self.listOfTexture[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):
            """
            Called when the user selects an element.
            """
            # I only use the checkbox to select list elemenmts
            """
            if mode == c4d.SELECTION_NEW:
                for tex in self.listOfTexture:
                    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
     
        def SetCheck(self, root, userdata, obj, column, checked, msg):
            """
            Called when the user clicks on a checkbox for an object in a
            `c4d.LV_CHECKBOX` column.
            """
            if checked:
                obj.Select()
            else:
                obj.Deselect()
    
            self.DoSomethingWithDialog()
    
     
        def IsChecked(self, root, userdata, obj, column):
            """
            Returns: (int): Status of the checkbox in the specified *column* for *obj*.
            """
            if obj.IsSelected:
                return c4d.LV_CHECKBOX_CHECKED | c4d.LV_CHECKBOX_ENABLED
            else:
                return c4d.LV_CHECKBOX_ENABLED
     
        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 in (ID_OTHER, ID_LONGFILENAME):
                text = obj.otherData if col == ID_OTHER else obj.longfilename
                canvas = drawinfo["frame"]
                textWidth = canvas.DrawGetTextWidth(text)
                textHeight = canvas.DrawGetFontHeight()
                xpos = drawinfo["xpos"]
                ypos = drawinfo["ypos"] + drawinfo["height"]
    
                if (drawinfo["width"] < textWidth):
                    while (drawinfo["width"] < textWidth):
                        if len(text) <= 4:
                            text = "..."
                            break
                        text = text[:-4] + "..."
                        textWidth = canvas.DrawGetTextWidth(text)
    
                textWidth = canvas.DrawGetTextWidth(text)
                drawinfo["frame"].DrawText(text, xpos, ypos - int(textHeight * 1.1))
    
            if col == ID_FILESIZE:
                text = obj.filesize
                canvas = drawinfo["frame"]
                # w = geUserArea.DrawGetTextWidth(name)
                h = canvas.DrawGetFontHeight()
                # xpos = drawinfo["xpos"] + 10
                xpos = drawinfo["xpos"] + drawinfo["width"] - canvas.DrawGetTextWidth(text)
                ypos = drawinfo["ypos"] + drawinfo["height"]
                drawinfo["frame"].DrawText(text, xpos, ypos - int(h * 1.1))
    
        def DoubleClick(self, root, userdata, obj, col, mouseinfo):
            """
            Called when the user double-clicks on an entry in the TreeView.
     
            Returns:
              (bool): True if the double-click was handled, False if the
                default action should kick in. The default action will invoke
                the rename procedure for the object, causing `SetName()` to be
                called.
            """
            c4d.gui.MessageDialog("You clicked on " + str(obj))
            return True
     
        def DeletePressed(self, root, userdata):
            "Called when a delete event is received."
            for tex in reversed(self.listOfTexture):
                if tex.IsSelected:
                    self.listOfTexture.remove(tex)
    
    
    class TestDialog(c4d.gui.GeDialog):
        _treegui = None  # Our CustomGui TreeView
        # _listView = ListView()  # Our Instance of c4d.gui.TreeViewFunctions
    
        def __init__(self):
            """
            """
            # Create an instance of ListView and give it access to the dialog
            # which carries it.
            self._listView = ListView(host=self)
            self.overall = len(self._listView.listOfTexture)
    
        def CreateLayout(self):
            # Create the TreeView GUI.
            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, True)  # True if no lines should be drawn.
            customgui.SetBool(c4d.TREEVIEW_MOVE_COLUMN, True)  # 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, False)  # Suppresses the rename popup when the user presses enter.
    
            if self.GroupBegin(id=1000, flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, rows=2, cols=1, groupflags=c4d.BORDER_OUT):
                self.GroupBorderSpace(left=5, top=5, right=5, bottom=5)
                self.GroupBorderNoTitle(borderstyle=c4d.BORDER_NONE)
    
                if self.GroupBegin(id=1001, flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, rows=2, cols=3, groupflags=c4d.BORDER_OUT):
                    self.GroupBorderNoTitle(borderstyle=c4d.BORDER_NONE)
                    self._treegui = self.AddCustomGui(TREEVIEW, c4d.CUSTOMGUI_TREEVIEW, "", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, minw=430, minh=160, customdata=customgui)
                    if not self._treegui:
                        print("[ERROR]: Could not create TreeView")
                        return False
                    self.GroupEnd()
    
                if self.GroupBegin(id=1002, flags=c4d.BFH_FIT | c4d.BFV_FIT, rows=2, cols=3, groupflags=c4d.BORDER_OUT):
                    self.GroupBorderNoTitle(borderstyle=c4d.BORDER_NONE)
    
                    self.AddStaticText(HOW_MANY, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_LEFT | c4d.BFH_SCALE, name="Selected: 0 / " + str(self.overall))
                    self.AddStaticText(HOW_MANY_MB, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_LEFT | c4d.BFH_SCALE, name="Filesize Sum: __________")
                    self.AddButton(MY_BUTON, c4d.BFH_CENTER, name="Enable me by check-boxing")
                    self.Enable(MY_BUTON, False)
                    self.GroupEnd()
    
                self.GroupEnd()
    
            return True
    
        def calc_selected(self):
            """this is a helper to calculate the selected elements and to enable the button
    
            :return: # slected and sum of the selecteed filsize
            """
            selected = 0
            filsizesum = 0
            self.overall = len(self._listView.listOfTexture)  # update our count
    
            for fileitem in self._listView.listOfTexture:
                if fileitem.IsSelected is True:
                    filsizesum += fileitem.filesize
                    selected += 1
    
            if selected > 0:
                self.Enable(MY_BUTON, True)
            else:
                self.Enable(MY_BUTON, False)
    
            sel_string = "Selected: " + str(selected) + " / " + str(self.overall)
            self.SetString(HOW_MANY, sel_string)
    
            mb_string = "Filesize Sum: " + str(filsizesum)
            self.SetString(HOW_MANY_MB, mb_string)
    
            return selected, filsizesum
    
        def InitValues(self):
            # Initialize the column layout for the TreeView.
            layout = c4d.BaseContainer()
            layout.SetLong(ID_CHECKBOX, c4d.LV_CHECKBOX)
            layout.SetLong(ID_NAME, c4d.LV_TREE)
            layout.SetLong(ID_LONGFILENAME, c4d.LV_USER)
            layout.SetLong(ID_OTHER, c4d.LV_USER)
            layout.SetLong(ID_FILESIZE, c4d.LV_USER)
            self._layout = layout
            self._treegui.SetLayout(5, layout)
     
            # Set the header titles.
            self._treegui.SetHeaderText(ID_CHECKBOX, "Check")
            self._treegui.SetHeaderText(ID_NAME, "Name")
            self._treegui.SetHeaderText(ID_LONGFILENAME, "Long Filename")
            self._treegui.SetHeaderText(ID_OTHER, "Other")
            self._treegui.SetHeaderText(ID_FILESIZE, "Filesize")
    
            self._treegui.Refresh()
     
            # Set TreeViewFunctions instance used by our CUSTOMGUI_TREEVIEW
            self._treegui.SetRoot(self._treegui, self._listView, None)
    
            return True
     
        def Command(self, id, msg):
            # Click on button
            if id == MY_BUTON:
                newID = int(len(self._listView.listOfTexture) + 1)
                tex = TextureObject()
                tex.texturePath = "Some new data " + str(newID)
                tex.longfilename = TextureObject.RandomString(20, 40)
                self._listView.listOfTexture.append(tex)
                self.calc_selected()
                self._treegui.Refresh()
    
            return True
    
     
    class MenuCommand(c4d.plugins.CommandData):
        dialog = None
     
        def Execute(self, doc):
            if self.dialog is None:
                self.dialog = TestDialog()
            return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, defaulth=300, defaultw=430)
     
        def RestoreLayout(self, sec_ref):
            if self.dialog is None:
                self.dialog = TestDialog()
            return self.dialog.Restore(PLUGIN_ID, secret=sec_ref)
     
     
    def main():
        c4d.plugins.RegisterCommandPlugin(
            PLUGIN_ID, "Python TreeView Example", 0, None, "Python TreeView Example", MenuCommand())
    
    
    if __name__ == "__main__":
        main()
    
    
    posted in General Talk •
    Wish / request: c4d.CallComand()

    Dear SDK Team,

    I would like to propose an idea for the c4d.CallComand()

    I often call callcomand in my scripts on vast lists of objects in succession, which is not optimal. Therefore I would like to propose an optional Paramtere to pass a list to the callcomand to execute.

    Similar to the utils.SendModelingCommand()

    Why: Because the internal Callcomand is faster than any self programed solution in python only the overhead of reapeataly calling it hinders its full potential.

    Things to be solved: What happens to a callcomand which already needs more than one object ... perhaps a list of lists ?

    Hope I am not talking total nonsense here but I am as of right now already watching a 3 hour callcomand loop ... and it will probably take all day ... losing that overhead would shafe of more than minutes in my case ...

    Yes I know I could learn C++ from zero and build a full solution but I think this is unrealistic in the short midterm. 😉

    kind regards
    mogh

    posted in General Talk •
    RE: Layers checker

    Beginner solution:
    If you do not need a certain layer you could also implement the call comand "Delete unused layers"
    Its not pretty but beats any convulated self written code if it is not called to often.

    c4d.CallCommand(100004760) # Remove unused layers

    cheers
    mogh

    posted in Cinema 4D SDK •
    Invoke Parent Function inside / outside class (TreeView)

    Dear developers,

    My topic seems a bit cryptic, but I am lacking the proper chargon to be more precise.

    I have my TreeViewFunctions with a list of objects with values.
    I want a button to activate and the sum selected and the sum of values of the object calculated outside the Treeview Gui hence I want to display it outside (my thinking might not be correct route to success) , when the user check marks an element.

    I've read about the Python "super()" thing but could not implement anything remotely working in my case. I once read in the documentation about passing gui to parents but can't find its any more. Anyway I tried a lot ... I know this is a broad OOP question but hence its tied to the treeview I try my luck here anyway.

    The use-case is:
    Users selects elements -> display value on the fly -> let user interact (in my case import)

    2022-02-26-Window_000060.jpg

    My Helper -> def calc_selected(self):

    Thanks in advance.
    Mogh

    """
    Adapted from:
        https://plugincafe.maxon.net/topic/10654/14102_using-customgui-listview/2
    """
    import c4d
    import random
     
    # Be sure to use a unique ID obtained from http://www.plugincafe.com/.
    PLUGIN_ID = 1000010  # TEST ID ONLY
     
    # TreeView Column IDs.
    ID_CHECKBOX = 1
    ID_NAME = 2
    ID_OTHER = 3
    ID_LONGFILENAME = 4
    MY_BUTON = 5
    HOW_MANY = 6
    ID_FILESIZE = 7
    HOW_MANY_MB = 8
    MY_CALC = 9
    
    TREEVIEW = 99
    
    # A tuple of characters to select from (a-z).
    CHARACTERS = tuple( chr ( n) for n in range(97, 122))
    
    
    class TextureObject(object):
        """
        Class which represent a texture, aka an Item in our list
        """
        def __init__(self):
            self.texturePath = TextureObject.RandomString(5, 10)
            self.otherData = TextureObject.RandomString(5, 20)
            self.longfilename = "-"
            self._selected = False
            self.filesize = TextureObject.RandomNumber()
    
        @staticmethod
        def RandomString(minLength, maxLength):
            """Returns a string of random characters with a length between 
            #minLength and #maxLength.
    
            The characters are taken from the 97 (a) to 122 (z) ASCII range.
            """
            return "".join(
                (random.choice(CHARACTERS) for _ in range(minLength, maxLength)))
    
        @staticmethod
        def RandomNumber():
            return random.randrange(1, 99)
    
        @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.texturePath
     
     
    class ListView(c4d.gui.TreeViewFunctions):
     
        def __init__(self):
            """
            """
            # Add ten mock data texture objects.
            self.listOfTexture = [TextureObject() for _ in range(10)]
    
        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 == ID_NAME:
                return area.DrawGetTextWidth(obj.texturePath) + 5
            if col == ID_OTHER:
                return area.DrawGetTextWidth(obj.otherData) + 5
            if col == ID_LONGFILENAME:
                return area.DrawGetTextWidth(obj.longfilename) + 5
                
            return width
    
        def IsMoveColAllowed(self, root, userdata, lColID):
            # The user is allowed to move all columns.
            # TREEVIEW_MOVE_COLUMN must be set in the container of AddCustomGui.
            return True
     
        def GetFirst(self, root, userdata):
            """
            Return the first element in the hierarchy, or None if there is no element.
            """
            rValue = None if not self.listOfTexture else self.listOfTexture[0]
            return rValue
     
        def GetDown(self, root, userdata, obj):
            """
            Return a child of a node, since we only want a list, we return None everytime
            """
            return None
     
        def GetNext(self, root, userdata, obj):
            """
            Returns the next Object to display after arg:'obj'
            """
            rValue = None
            currentObjIndex = self.listOfTexture.index(obj)
            nextIndex = currentObjIndex + 1
            if nextIndex < len(self.listOfTexture):
                rValue = self.listOfTexture[nextIndex]
     
            return rValue
     
        def GetPred(self, root, userdata, obj):
            """
            Returns the previous Object to display before arg:'obj'
            """
            rValue = None
            currentObjIndex = self.listOfTexture.index(obj)
            predIndex = currentObjIndex - 1
            if 0 <= predIndex < len(self.listOfTexture):
                rValue = self.listOfTexture[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):
            """
            Called when the user selects an element.
            """
            # I only use the checkbox to select list elemenmts
            """
            if mode == c4d.SELECTION_NEW:
                for tex in self.listOfTexture:
                    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
     
        def SetCheck(self, root, userdata, obj, column, checked, msg):
            """
            Called when the user clicks on a checkbox for an object in a
            `c4d.LV_CHECKBOX` column.
            """
            if checked:
                obj.Select()
            else:
                obj.Deselect()
     
        def IsChecked(self, root, userdata, obj, column):
            """
            Returns: (int): Status of the checkbox in the specified *column* for *obj*.
            """
            if obj.IsSelected:
                return c4d.LV_CHECKBOX_CHECKED | c4d.LV_CHECKBOX_ENABLED
            else:
                return c4d.LV_CHECKBOX_ENABLED
     
        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 in (ID_OTHER, ID_LONGFILENAME):
                text = obj.otherData if col == ID_OTHER else obj.longfilename
                canvas = drawinfo["frame"]
                textWidth = canvas.DrawGetTextWidth(text)
                textHeight = canvas.DrawGetFontHeight()
                xpos = drawinfo["xpos"]
                ypos = drawinfo["ypos"] + drawinfo["height"]
    
                if (drawinfo["width"] < textWidth):
                    while (drawinfo["width"] < textWidth):
                        if len(text) <= 4:
                            text = "..."
                            break
                        text = text[:-4] + "..."
                        textWidth = canvas.DrawGetTextWidth(text)
    
                textWidth = canvas.DrawGetTextWidth(text)
                drawinfo["frame"].DrawText(text, xpos, ypos - int(textHeight * 1.1))
    
            if col == ID_FILESIZE:
                text = obj.filesize
                canvas = drawinfo["frame"]
                # w = geUserArea.DrawGetTextWidth(name)
                h = canvas.DrawGetFontHeight()
                # xpos = drawinfo["xpos"] + 10
                xpos = drawinfo["xpos"] + drawinfo["width"] - canvas.DrawGetTextWidth(text)
                ypos = drawinfo["ypos"] + drawinfo["height"]
                drawinfo["frame"].DrawText(text, xpos, ypos - int(h * 1.1))
    
        def DoubleClick(self, root, userdata, obj, col, mouseinfo):
            """
            Called when the user double-clicks on an entry in the TreeView.
     
            Returns:
              (bool): True if the double-click was handled, False if the
                default action should kick in. The default action will invoke
                the rename procedure for the object, causing `SetName()` to be
                called.
            """
            c4d.gui.MessageDialog("You clicked on " + str(obj))
            return True
     
        def DeletePressed(self, root, userdata):
            "Called when a delete event is received."
            for tex in reversed(self.listOfTexture):
                if tex.IsSelected:
                    self.listOfTexture.remove(tex)
    
    
    class TestDialog(c4d.gui.GeDialog):
        _treegui = None  # Our CustomGui TreeView
        _listView = ListView()  # Our Instance of c4d.gui.TreeViewFunctions
    
        def __init__(self):
            self.overall = len(self._listView.listOfTexture)
    
        def CreateLayout(self):
            # Create the TreeView GUI.
            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, True)  # True if no lines should be drawn.
            customgui.SetBool(c4d.TREEVIEW_MOVE_COLUMN, True)  # 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, False)  # Suppresses the rename popup when the user presses enter.
    
            if self.GroupBegin(id=1000, flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, rows=3, cols=1, groupflags=c4d.BORDER_OUT):
                self.GroupBorderSpace(left=5, top=5, right=5, bottom=5)
                self.GroupBorderNoTitle(borderstyle=c4d.BORDER_NONE)
    
                if self.GroupBegin(id=1001, flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, rows=2, cols=3, groupflags=c4d.BORDER_OUT):
                    self.GroupBorderNoTitle(borderstyle=c4d.BORDER_NONE)
                    self._treegui = self.AddCustomGui(TREEVIEW, c4d.CUSTOMGUI_TREEVIEW, "", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, minw=430, minh=160, customdata=customgui)
                    if not self._treegui:
                        print("[ERROR]: Could not create TreeView")
                        return False
                    self.GroupEnd()
    
                if self.GroupBegin(id=1002, flags=c4d.BFH_FIT | c4d.BFV_FIT, rows=2, cols=4, groupflags=c4d.BORDER_OUT):
                    self.GroupBorderNoTitle(borderstyle=c4d.BORDER_NONE)
    
                    self.AddStaticText(HOW_MANY, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_LEFT | c4d.BFH_SCALE, name="Selected: 0 / " + str(self.overall))
                    self.AddStaticText(HOW_MANY_MB, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_LEFT | c4d.BFH_SCALE, name="Filesize Sum: ____")
                    self.AddButton(MY_CALC, c4d.BFH_CENTER, name="Calc Manual")
                    self.AddButton(MY_BUTON, c4d.BFH_CENTER, name="Enable me by check-boxing")
                    self.Enable(MY_BUTON, False)
                    self.GroupEnd()
    
                if self.GroupBegin(id=1002, flags=c4d.BFH_FIT | c4d.BFV_FIT, rows=2, cols=3, groupflags=c4d.BORDER_OUT):
                    self.GroupBorderSpace(left=5, top=5, right=5, bottom=5)
                    self.GroupBorderNoTitle(c4d.BORDER_ACTIVE_3)
                    self.AddStaticText(1003, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_CENTER | c4d.BFH_SCALE, name="How do I invoke action from inside the treegui class?")
                    self.GroupEnd()
                self.GroupEnd()
    
            return True
    
        def calc_selected(self, autoactivate):
            """
            this is a helper to calculate the selected elements and to enable the button
            I do NOT know how to trigger this everytime a user clicks on a checkbox in the treegui class
    
            :return: # slected and sum of the selecteed filsize
            """
            selected = 0
            filsizesum = 0
            for fileitem in self._listView.listOfTexture:
                if fileitem.IsSelected is True:
                    filsizesum += fileitem.filesize
                    selected += 1
    
            if selected > 0 and autoactivate:
                self.Enable(MY_BUTON, True)
    
            sel_string = "Selected: " + str(selected) + " / " + str(self.overall)
            self.SetString(HOW_MANY, sel_string)
    
            mb_string = "Filesize Sum: " + str(filsizesum)
            self.SetString(HOW_MANY_MB, mb_string)
    
            return selected, filsizesum
    
        def InitValues(self):
            # Initialize the column layout for the TreeView.
            layout = c4d.BaseContainer()
            layout.SetLong(ID_CHECKBOX, c4d.LV_CHECKBOX)
            layout.SetLong(ID_NAME, c4d.LV_TREE)
            layout.SetLong(ID_LONGFILENAME, c4d.LV_USER)
            layout.SetLong(ID_OTHER, c4d.LV_USER)
            layout.SetLong(ID_FILESIZE, c4d.LV_USER)
            self._layout = layout
            self._treegui.SetLayout(5, layout)
     
            # Set the header titles.
            self._treegui.SetHeaderText(ID_CHECKBOX, "Check")
            self._treegui.SetHeaderText(ID_NAME, "Name")
            self._treegui.SetHeaderText(ID_LONGFILENAME, "Long Filename")
            self._treegui.SetHeaderText(ID_OTHER, "Other")
            self._treegui.SetHeaderText(ID_FILESIZE, "Filesize")
    
            self._treegui.Refresh()
     
            # Set TreeViewFunctions instance used by our CUSTOMGUI_TREEVIEW
            self._treegui.SetRoot(self._treegui, self._listView, None)
    
            return True
     
        def Command(self, id, msg):
            # Click on button
            if id == MY_BUTON:
                newID = int(len(self._listView.listOfTexture) + 1)
                tex = TextureObject()
                tex.texturePath = "Some new data " + str(newID)
                tex.longfilename = TextureObject.RandomString(20, 40)
                self._listView.listOfTexture.append(tex)
                self._treegui.Refresh()
     
            if id == MY_CALC:
                self.calc_selected(False)
                # print(self.calc_selected(False))
    
            return True
    
     
    class MenuCommand(c4d.plugins.CommandData):
        dialog = None
     
        def Execute(self, doc):
            if self.dialog is None:
                self.dialog = TestDialog()
            return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, defaulth=300, defaultw=430)
     
        def RestoreLayout(self, sec_ref):
            if self.dialog is None:
                self.dialog = TestDialog()
            return self.dialog.Restore(PLUGIN_ID, secret=sec_ref)
     
     
    def main():
        c4d.plugins.RegisterCommandPlugin(
            PLUGIN_ID, "Python TreeView Example", 0, None, "Python TreeView Example", MenuCommand())
    
    
    if __name__ == "__main__":
        main()
    
    
    
    posted in General Talk •
    RE: Treeview Column adjust

    Thanks ferdinand as allways you are the best.

    I call this solved, the problems I encounter in my project are my own ... after cleaning my code - solving sorting ascending / descening will be next ... 😉

    posted in Cinema 4D SDK •
    RE: Treeview Column adjust

    @ferdinand Thank you again, and I am sorry, for not following the guidelines, need to print them out I guess. Also forgot to "Ask a Question"

    I understand the concept (or perhaps not at all) but even in your example it only takes the string of the "first" column (because obj always returns its "name" not its other variables) and after putting a print inside the isinstance() I figured its never trigered ?

    I modified the code so the button inserts a long string after the treeview was established to illustrate it.

    Regarding Cloumn -> I guess I have to evaluate the column and then get the coresponding variable from the object to measure the right width?

            print(obj, col, area.DrawGetTextWidth(obj))
    
                    if isinstance(obj, str):        
                        # 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.        
                        width = area.DrawGetTextWidth(obj)        
                        print(width)        
                    return width
    

    Full code with working Button:

    """Example for setting the column width of a tree view by the width of its
    items.
    
    The only changes which have been made in comparison to the original code can
    be found in TextureObject.__init__(), TextureObject.RandomString() and 
    ListView.GetColumnWidth(). The tree view items #TextureObject now generate
    random #texturePath and #otherData strings and the treeview scales its columns
    to the length of these strings.
    
    Adapted from:
        https://plugincafe.maxon.net/topic/10654/14102_using-customgui-listview/2
    """
    import c4d
    import random
     
    # Be sure to use a unique ID obtained from http://www.plugincafe.com/.
    PLUGIN_ID = 1000010 # TEST ID ONLY
     
    # TreeView Column IDs.
    ID_CHECKBOX = 1
    ID_NAME = 2
    ID_OTHER = 3
    ID_LONGFILENAME = 4
    
    # A tuple of characters to select from (a-z).
    CHARACTERS = tuple( chr ( n) for n in range(97, 122))
    
    
    class TextureObject(object):
        """
        Class which represent a texture, aka an Item in our list
        """
        def __init__(self):
            self.texturePath = TextureObject.RandomString(5, 10)
            self.otherData = TextureObject.RandomString(5, 20)
            self.longfilename = "-"
            self._selected = False
    
        @staticmethod
        def RandomString(minLength: int, maxLength: int) -> str:
            """Returns a string of random characters with a length between 
            #minLength and #maxLength.
    
            The characters are taken from the 97 (a) to 122 (z) ASCII range.
            """
            return "".join(
                (random.choice(CHARACTERS) for _ in range(minLength, maxLength)))
     
        @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.texturePath
     
     
    class ListView(c4d.gui.TreeViewFunctions):
     
        def __init__(self):
            """
            """
            # Add ten mock data texture objects.
            self.listOfTexture = [TextureObject() for _ in range(10)]
    
        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 content of 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
            # For all calls for cells which contain a string item ...
            print(obj, col, area.DrawGetTextWidth(obj))
    
            if isinstance(obj, str):
                # 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.
                width = area.DrawGetTextWidth(obj)
                print(width)
            return width
    
        def IsMoveColAllowed(self, root, userdata, lColID):
            # The user is allowed to move all columns.
            # TREEVIEW_MOVE_COLUMN must be set in the container of AddCustomGui.
            return True
     
        def GetFirst(self, root, userdata):
            """
            Return the first element in the hierarchy, or None if there is no element.
            """
            rValue = None if not self.listOfTexture else self.listOfTexture[0]
            return rValue
     
        def GetDown(self, root, userdata, obj):
            """
            Return a child of a node, since we only want a list, we return None everytime
            """
            return None
     
        def GetNext(self, root, userdata, obj):
            """
            Returns the next Object to display after arg:'obj'
            """
            rValue = None
            currentObjIndex = self.listOfTexture.index(obj)
            nextIndex = currentObjIndex + 1
            if nextIndex < len(self.listOfTexture):
                rValue = self.listOfTexture[nextIndex]
     
            return rValue
     
        def GetPred(self, root, userdata, obj):
            """
            Returns the previous Object to display before arg:'obj'
            """
            rValue = None
            currentObjIndex = self.listOfTexture.index(obj)
            predIndex = currentObjIndex - 1
            if 0 <= predIndex < len(self.listOfTexture):
                rValue = self.listOfTexture[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):
            """
            Called when the user selects an element.
            """
            if mode == c4d.SELECTION_NEW:
                for tex in self.listOfTexture:
                    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
     
        def SetCheck(self, root, userdata, obj, column, checked, msg):
            """
            Called when the user clicks on a checkbox for an object in a
            `c4d.LV_CHECKBOX` column.
            """
            if checked:
                obj.Select()
            else:
                obj.Deselect()
     
        def IsChecked(self, root, userdata, obj, column):
            """
            Returns: (int): Status of the checkbox in the specified *column* for *obj*.
            """
            if obj.IsSelected:
                return c4d.LV_CHECKBOX_CHECKED | c4d.LV_CHECKBOX_ENABLED
            else:
                return c4d.LV_CHECKBOX_ENABLED
     
        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 == ID_OTHER:
                name = obj.otherData
                geUserArea = drawinfo["frame"]
                w = geUserArea.DrawGetTextWidth(name)
                h = geUserArea.DrawGetFontHeight()
                xpos = drawinfo["xpos"]
                ypos = drawinfo["ypos"] + drawinfo["height"]
                drawinfo["frame"].DrawText(name, xpos, ypos - int(h * 1.1))
    
            if col == ID_LONGFILENAME:
                name = obj.longfilename
                geUserArea = drawinfo["frame"]
                w = geUserArea.DrawGetTextWidth(name)
                h = geUserArea.DrawGetFontHeight()
                xpos = drawinfo["xpos"]
                ypos = drawinfo["ypos"] + drawinfo["height"]
                drawinfo["frame"].DrawText(name, xpos, ypos - int(h * 1.1))
     
        def DoubleClick(self, root, userdata, obj, col, mouseinfo):
            """
            Called when the user double-clicks on an entry in the TreeView.
     
            Returns:
              (bool): True if the double-click was handled, False if the
                default action should kick in. The default action will invoke
                the rename procedure for the object, causing `SetName()` to be
                called.
            """
            c4d.gui.MessageDialog("You clicked on " + str(obj))
            return True
     
        def DeletePressed(self, root, userdata):
            "Called when a delete event is received."
            for tex in reversed(self.listOfTexture):
                if tex.IsSelected:
                    self.listOfTexture.remove(tex)
    
    
    class TestDialog(c4d.gui.GeDialog):
        _treegui = None  # Our CustomGui TreeView
        _listView = ListView()  # Our Instance of c4d.gui.TreeViewFunctions
     
        def CreateLayout(self):
            # Create the TreeView GUI.
            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, True)  # True if no lines should be drawn.
            customgui.SetBool(c4d.TREEVIEW_MOVE_COLUMN, True)  # 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, False)  # Suppresses the rename popup when the user presses enter.
     
            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):
            # Initialize the column layout for the TreeView.
            layout = c4d.BaseContainer()
            layout.SetLong(ID_CHECKBOX, c4d.LV_CHECKBOX)
            layout.SetLong(ID_NAME, c4d.LV_TREE)
            layout.SetLong(ID_LONGFILENAME, c4d.LV_USER)
            layout.SetLong(ID_OTHER, c4d.LV_USER)
    
            self._treegui.SetLayout(4, layout)
     
            # Set the header titles.
            self._treegui.SetHeaderText(ID_CHECKBOX, "Check")
            self._treegui.SetHeaderText(ID_NAME, "Name")
            self._treegui.SetHeaderText(ID_LONGFILENAME, "Long Filename")
            self._treegui.SetHeaderText(ID_OTHER, "Other")
    
            self._treegui.Refresh()
     
            # Set TreeViewFunctions instance used by our CUSTOMGUI_TREEVIEW
            self._treegui.SetRoot(self._treegui, self._listView, None)
            return True
     
        def Command(self, id, msg):
            # Click on button
            if id == 1001:
                # Add data to our DataStructure (ListView)
                newID = int(len(self._listView.listOfTexture) + 1)
                # print(newID)
                # newID = "T{}".format(newID)
                # print(newID)
                # tex = TextureObject(newID)
                tex = TextureObject()
                tex.texturePath = "Some new data"
                tex.longfilename = TextureObject.RandomString(20, 80)
                self._listView.listOfTexture.append(tex)
                # Refresh the TreeView
                self._treegui.Refresh()
     
            return True
     
     
    class MenuCommand(c4d.plugins.CommandData):
        dialog = None
     
        def Execute(self, doc):
            if self.dialog is None:
                self.dialog = TestDialog()
            return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, defaulth=600, defaultw=600)
     
        def RestoreLayout(self, sec_ref):
            if self.dialog is None:
                self.dialog = TestDialog()
            return self.dialog.Restore(PLUGIN_ID, secret=sec_ref)
     
     
    def main():
        c4d.plugins.RegisterCommandPlugin(
            PLUGIN_ID, "Python TreeView Example", 0, None, "Python TreeView Example", MenuCommand())
    
    
    if __name__ == "__main__":
        main()
    
    

    thank you
    mogh

    posted in Cinema 4D SDK •
    RE: Treeview Column adjust

    I'am having Forum troubles posting ... is there a max char limit ?

    Replying here with a long answer with code gives me "Error: error"

    kind regrads
    mogh

    posted in Cinema 4D SDK •
    Treeview Column adjust

    Dear developers,

    is there a solution for displaying the columns in the right width when the treeview is populated with data?
    I can get the width of each cell with geUserArea.DrawGetTextWidth("somestring"), but I do not know how to "readjust" the columns to the right width ...

    class listview():
    
        def GetColumnWidth(self, root, userdata, obj, col, area):
            return 40
    
    def DrawCell():
        
        geUserArea.DrawGetTextWidth("somestring")
    

    current status see the overlapping on the date
    2022-02-21 08_20_34-Cad File Importer 0.66.png
    desired output
    2022-02-21 08_20_58-Cad File Importer 0.66.png

    regarding code, it builds on the treeview list floating around here in the forums. I do not know of a SDK Example?

    thanks in advance

    posted in Cinema 4D SDK •
    RE: Best practice getting all objects in a certain Null

    Found the problem I tried to Kill a document which was not alive, don't know if this is necessary with a merge.

        if c4d.C4DAtom.IsAlive(temp):
            c4d.documents.KillDocument(temp)
    

    And another gotcha c4d.documents.SetActiveDocument(temp) seems to be mandatory if you want to use CallCommand() -> and do not to forget to set the doc back to active after your routine.

    Thank you

    posted in Cinema 4D SDK •
    RE: Best practice getting all objects in a certain Null

    How do I catch / prevent a "ReferenceError: the object 'c4d.documents.BaseDocument' is not alive"
    when the user has an unsaved / unclicked / unactive doc as master ?

    my problem ist the

    if not c4d.documents.MergeDocument(doc, mfs, loadflags=flags):
    

    it fails while your

    if c4d.documents.MergeDocument(doc, mfs, loadflags=flags):
    

    is error free

    thanks

    posted in Cinema 4D SDK •
    RE: Best practice getting all objects in a certain Null

    @ferdinand Thanks, you pointed me to my error:

    The above code needs these scene flags to work properly ....
    as the MergeDocument() merges only with certain flags ... (c4d.SCENEFILTER_MERGESCENE will not work this is a gotcha ...)

    c4d.documents.MergeDocument(doc, mfs, loadflags=c4d.SCENEFILTER_OBJECTS , thread=None ):

    So to update my blueprint:

    1. LoadDocument() to tempdoc (need to test this ...)
    2. Cleanup
    3. save tempdoc to MemoryFileStruct()
    4. merge "open/active" c4d File with MemoryFileStruct() (similar to prototype above)

    @SDKTeam
    I will update and set to solved when I do get a prototype working. please be patient.

    thanks
    mogh

    posted in Cinema 4D SDK •
    RE: Best practice getting all objects in a certain Null

    my WIP prototype, but the generated cubes are not "present" in the merged document yet.

    import c4d
    from c4d import gui
    #from c4d.documents import GetActiveDocument
    
    
    def create_obj(doc):
        obj = c4d.BaseObject(c4d.Ocube)
        obj.SetName("importedcube")
        doc.InsertObject(obj)
        c4d.EventAdd()
    
    def main():
            doc = c4d.documents.GetActiveDocument()
            print("Active Doc: ", doc.GetDocumentName())
            
            dirpath = r"c:\\"
            doctemp = None
           
            if doctemp==None:
                doctemp = c4d.documents.BaseDocument()
                doctemp.SetDocumentName("temp_import.c4d")
                doctemp.SetDocumentPath(dirpath)
                
                c4d.documents.InsertBaseDocument(doctemp) # calls set active allready
                #c4d.documents.SetActiveDocument(doctemp)
    
            create_obj(doctemp)
            create_obj(doctemp)
            
            """
            obj = doc.GetActiveObject()
            if obj is None:
                print("No active object")
                c4d.documents.KillDocument(doctemp)
                return        
            isolateDoc = c4d.documents.IsolateObjects(doctemp, [obj])
            """
    
            mfs = c4d.storage.MemoryFileStruct()
            mfs.SetMemoryWriteMode()
            c4d.documents.SaveDocument(doctemp, mfs, c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, c4d.FORMAT_C4DEXPORT)
            data = mfs.GetData()
            mfs.SetMemoryReadMode(data[0], data[1] )
    
            
            if c4d.documents.MergeDocument(doc, mfs, loadflags=c4d.SCENEFILTER_MERGESCENE, thread=None ): #  c4d.SCENEFILTER_MERGESCENE | c4d.SCENEFILTER_NOUNDO, 
                print("merged",  mfs)
    
            
            #doctemp.Flush()
            c4d.documents.KillDocument(doctemp)
            
            #c4d.documents.SetActiveDocument(doc)
    
    
    
    # Execute main()
    if __name__=='__main__':
        c4d.CallCommand(13957) # clear concole
        main()
    
    posted in Cinema 4D SDK •
    RE: Best practice getting all objects in a certain Null

    As I am already running into problems with my current cleanup which proceses the tree more than once -> I think i have to open the import into "memory file structure" but I am not really clear what you mean from a functional standpoint.

    There are several interesting builtin function.

    c4d.documents.MergeDocument(doc, name, loadflags, thread) # <- used ATM
    
    c4d.documents.LoadFile(name)
    c4d.documents.LoadDocument(name, loadflags, thread=None)
    
    c4d.documents.IsolateObjects(doc, t_objects) # whats the 
    
    

    Whats the difference between MergeDocument and LoadDocument with SCENEFILTER_MERGESCENE flags ?
    Why has MergeDocument a SCENEFILTER_MERGESCENE Flag ?

    are my asumption right:

    1. create a new DOC e.g. tempdoc
    2. LoadFile/ LoadDocument / MergeDocument into that - which one ?
    3. copy objects or merge doc again ?

    thanks in advance
    mogh

    posted in Cinema 4D SDK •
    RE: Draw Icon (maxon id) into treeview list geUserArea()

    Thanks, @m_magalhaes
    yes my code is inside the drawcell() method.

    I didn' have any luck with c4d.gui.GetIcon(lIconID)
    but i got c4d.bitmaps.InitResourceBitmap(resource_id)
    working.

    here are my 3 lines of code that got me an icon.

    ICON_SIZE = drawinfo["height"]
    bmp = c4d.bitmaps.InitResourceBitmap(12098)
    geUserArea.DrawBitmap(bmp, drawinfo["xpos"], drawinfo["ypos"], ICON_SIZE, ICON_SIZE, 0, 0, bmp.GetBw(), bmp.GetBh(), c4d.BMP_ALLOWALPHA)
    

    kind regards
    mogh

    posted in Cinema 4D SDK •
    RE: Best practice getting all objects in a certain Null

    Thanks @m_magalhaes

    yes I can get the name (of the first Object) and check that and getup till I reach it, still I am worried that I can not say for certain what "objecst" c4d.documents.MergeDocument() gave me ...

    "certain Null" is not defined other than it is inserted at the top from C4D ... so i guess I have to get the Null by listing all root nulls bevore and after the import.

    Sorry I was a bit unclear and its 2 question in one as I am still "brainstoring"

    kind regards
    mogh

    posted in Cinema 4D SDK •