The Maxon SDK Team is currently short staffed due to the winter holidays. No forum support is being provided between 15/12/2025 and 5/1/2026. For details see Maxon SDK 2025 Winter Holidays.
  • Python Plugin Development

    python r21
    3
    0 Votes
    3 Posts
    675 Views
    FSSF
    Hi Ferdinand, thank you for your reply. You were indeed correct, my imports were not working due to bugs. If software bugs had protein, i alone could end world hunger. I was able to solve them after providing the -nogui argument, which then piped out the errors again to the commandline. This worked without in the old version of the plugin, due to it not using any imports besides the local ones (none in the \AppData\Roaming\Python\{PYTHON_VERSION}). As a result the commandline put out errors. If using imports though, the commandline swallowed the output (error+stacktrace) and stayed blank until the plugin was erroring out and the system continued with other plugin calls and the CONSTRING NOT FREED at the end.
  • Wish / request: c4d.CallComand()

    7
    0 Votes
    7 Posts
    1k Views
    a_blockA
    Sorry, my bad, different forum, different rules... I had forgotten, we do not have PMs in here. Send me an email to "job AT andreasblock dot de".
  • Invoke Parent Function inside / outside class (TreeView)

    3
    1
    0 Votes
    3 Posts
    884 Views
    M
    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://developers.maxon.net/forum/topic/10654/14102_using-customgui-listview/2 """ import c4d import random # Be sure to use a unique ID obtained from [URL-REMOVED] 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() [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
  • fbx import missing animation

    2
    0 Votes
    2 Posts
    555 Views
    ferdinandF
    Hello @christajj, welcome to the Plugin Café and thank you for reaching out to us. These are the forums of the development community of Cinema 4D. The subjects discussed in these forums are exclusively the APIs related to Cinema 4D. Your question is therefore unfortunately off topic, even in our more broadly scope forum General Talk. When you require customer support from Maxon, you should contact us in our customer Support Center. Established and English-speaking Cinema 4D user communities can be found at Core 4D and CGTalk. Thank you for your understanding, Ferdinand
  • Looking for Developer of custom Mograph effector

    2
    0 Votes
    2 Posts
    734 Views
    ManuelM
    Hi, There is the EffectorData class that could help you to create your own effector. This class is only available on c++. With python the only option is to use the python effector. And that could be tricky because you need to retrieve the size of all clones. Doable but tricky imo. I hope that you will find a developer to do it, this might look easy to do but is harder than you might thought. Cheers, Manuel
  • particle direction driven by texture

    3
    2
    0 Votes
    3 Posts
    972 Views
    H
    Thank you alot Ferdinand for your time, thoughs and help. I really appreciate that:)' I will get my head in it and try to figure it out.
  • Xpreso plugin development

    python
    2
    0 Votes
    2 Posts
    476 Views
    ferdinandF
    Hello @rastan_cgi, Thank you for reaching out to us. This forum is targeted at software development with the Cinema 4D & Cineware SDK. Xpresso or Scene Nodes are not part of the scope of the forum and the support Maxon does deliver here. However, you already did post in the correct forum for asking an off-topic question, the General Talk forum. The community is welcome to discuss here topics that are adjacent to the Cinema 4D & Cineware SDKs, as for example Xpresso. But the SDK-Team cannot offer any support for these questions. If you seek an official answer from Maxon, you should contact user support. With that being said: Xpresso setups cannot automatically be converted into a Python or C++ plugin. You can provide a scene with a null object and your setup, but these workflows are not within the scope of the SDK-Team. When you seek help with reimplementing your Xpresso setup as a plugin, for example as a Python plugin, then we will need more information on what the Xpresso setup does. We can then tell you where you can find learning resources related to your goals, but you will have to write the code yourself. Cheers, Ferdinand
  • How To View 3D In Windows 10 PC?

    Locked
    3
    0 Votes
    3 Posts
    580 Views
    ferdinandF
    Hello @HerminioLehner, Thank you for reaching out to us. This is a forum dedicated to software development for Maxon Cinema 4D. It is unfortunately not the place to discuss media consumption in general or 3D movies in particular. You are going to be more successful with your question on www.blu-ray.com. I have closed this thread due to the reasons lined out above. Cheers, Ferdinand
  • Cinema 4D Xpresso

    2
    0 Votes
    2 Posts
    860 Views
    ManuelM
    Hi, Welcome to our forum. This forum scope is to support people that have questions regarding our API, you can have a look at our scope on this page. (Coding with python or c++) If by Xpresso you mean, having a python node inside your Xpresso and you have a question regarding our API, the Cinema 4D SDK category is the place to ask your question. If your question is how to use or build an Xpresso setup, you can contact our regular support, they might have some suggestion about where you can talk/ask your questions. Cheers, Manuel
  • Where to report a bug?

    2
    0 Votes
    2 Posts
    802 Views
    ManuelM
    Hi, if you want to report a bug in the maxon API you can use this forum in relation with the the SDK you are using (Cinema or Cineware) If you want to report a bug in Cinema4D you can use our regular support. Describe your issue and at least we can confirm or not if it's a bug. Cheers, Manuel
  • shutdown pc after render queue

    Moved
    4
    0 Votes
    4 Posts
    2k Views
    ferdinandF
    Hello @EnzoM, no worries, these rules are not always obvious which is why we point the out. About your task at hand: I have already moved your question to the correct Forum General Programming & Plugin Discussions where you can also ask for a (paid) third party developer. You should then also specify if you are willing to pay for a solution or not. But you should be aware that we mostly target here the upper end of Cinema 4D development, you are more likely to find a dev for quick job on core4d. If there was already a plugin for this, contacting its original author might be easiest path. About the context of your task: This does not apply here anymore, since this is not a coding question, so you have no context to specify Cheers, Ferdinand
  • R24.111: shiboken2 fails to load (Win10)

    python s24
    3
    1 Votes
    3 Posts
    927 Views
    ferdinandF
    Hello @jcooper, thank you for reaching out to us. First of all, I must point out that what you are trying to do is out of scope of support. We cannot support third party libraries as stated in our Forum Guidelines and we especially cannot support third party GUIs. The little help I can give you here is to say: There is currently a bug in R25 which will cause faulty installations when using pip and having a vanilla CPython installation of the same version on the system. The installation itself will work fine, but the import paths of both Pythons will become entangled in this case due CPython having some hardcoded import paths in its code pointing to the user directories. We have fixed this problem and the fix will be delivered with an upcoming release. You can check this easily by checking the installation paths of modules with the ```fileattribute of the module. When you are encountering the problem, it will be pointing towards yourCPython`` site-packages and not the one from Cinema. There is not much what you can do to fix this yourself (aside from monkey-patching our Python yourself). There is more than sys.path in Python, there is also sys.meta_path and relative imports, so just being able to import other packages in the same path is no guarantee that everything is fine. I cannot say much more with the given little information, and we can unfortunately also not support third party libraries. You should check if indeed is everything installed in the correct location. The problem you have could be related to what I describe under 1., but that bug did exist for quite some time, so it should have failed before. Cheers, Ferdinand
  • #recruitment Direct Link from Cinema 4D to D5 Render

    Moved
    2
    1 Votes
    2 Posts
    1k Views
    J
    Hey, @m_adam , thanks for your kindly upvote. Since I can't find how to send private messages within this forum, could I have a conversation with you through email? And my mail address is [email protected] Thanks:)
  • Noob wants to load custom palette

    python
    3
    0 Votes
    3 Posts
    632 Views
    R
    @cairyn Thanks a lot ... it works!
  • Maxon SDK Specialist job position available

    Moved
    1
    2 Votes
    1 Posts
    550 Views
    No one has replied
  • get length of stroke

    5
    0 Votes
    5 Posts
    1k Views
    ferdinandF
    Hello @InterfaceGuy, without any further questions, we will consider this topic as solved by Monday, the 25th and flag it accordingly. Thank you for your understanding, Ferdinand
  • Getting the offset of MoGraph clones

    6
    0 Votes
    6 Posts
    1k Views
    ferdinandF
    Hello @rui_mac, without any further questions or replies, we will consider this thread as solved by Monday the 20th and flag it accordingly. Thank you for your understanding, Ferdinand
  • Sorting cloner each n frame

    7
    0 Votes
    7 Posts
    1k Views
    ferdinandF
    Hello @Jengo, without any further questions or replies, we will consider this thread as solved by Monday the 20th and flag it accordingly. Thank you for your understanding, Ferdinand
  • Best way to display a bitmap in the viewport background

    5
    0 Votes
    5 Posts
    915 Views
    ferdinandF
    Hello @rui_mac, without any further questions or replies, we will consider this thread as solved by Monday the 20th and flag it accordingly. Thank you for your understanding, Ferdinand
  • Ways around the Python GIL

    10
    0 Votes
    10 Posts
    2k Views
    ferdinandF
    Hello @orestiskon, without any further questions or replies, we will consider this thread as solved by Monday the 20th and flag it accordingly. Thank you for your understanding, Ferdinand