Populate Userdata via Python - Please Help!



  • On 08/06/2015 at 00:17, xxxxxxxx wrote:

    Hello, as a beginner of C4D Python Scripting, I'm trying to find out how to populate & dynamically a userdata (dropdown - cycle ). When user add new object/spline under specific Null - I want it automatically be added to dropdown userdata. (I'm going to use it as a Python Node in my Xpresso Setup )

    Here is my non-working terrible code;
    What I want is;

    Search null (Profiles) - Get its children names 
    Populate Userdata as Dropdown (Userdata is located in "Options" null) like 01;Profile1 02;Profile2 03;Profile3
    http://www.dropbox.com/s/9f5mwlosm6oy39v/modify_userdata.c4d?dl=0

    😢

    import c4d
    from c4d import gui
    from c4d import documents

    def GetChildren(node) :
        global names
        
        options = doc.SearchObject("Options") # This is where userdata located
        profiles = doc.SearchObject("Profiles") # Get names of children from this null 
        userdata = options.GetUserDataContainer() #The master UD container
        
        if options is None:
            print "main controls not found"
            return
        count = len(profiles.GetChildren())
        
        if (node.GetChildren() != []) :
            for child in node.GetChildren() :
                GetChildren(child)
                names = []
                names = child.GetName()
                print names
                print count
                nextID = len(options.GetUserDataContainer()) - 1
                bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_STRING)
                cc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_STRING)
                bc[c4d.DESC_NAME] = 'Profiles'
                bc[c4d.DESC_CUSTOMGUI] = c4d.CUSTOMGUI_CYCLE
                #CUSTOMGUI_STRINGMULTI
                options.SetUserDataContainer([c4d.ID_USERDATA, 1], bc)
                
    def main() :
        GetChildren(Object)



  • On 08/06/2015 at 08:42, xxxxxxxx wrote:

    Hi and welcome to the PluginCafe!

    Thanks for the example scene.

    What's you're missing is the initialization and the way to setup a user data container.
    If you want a dropdown cycle, this is an integer parameter. So you've to retrieve an integer default container (DTYPE_LONG). Then set the parameter to use  the CUSTOMGUI_CYCLE and initialize its values with DESC_CYCLE.
    Also, you seem to try to recursively call GetChildren() for each child of the input object. I'm not sure this is really wanted.

    Note in your XPresso Python node, 'node' and 'profiles' variables references the same object. This could lead to problems if the input object is changed in the XPresso setup.

    Here's how GetChildren() function would look like:

    def GetChildren(node) :
        global names
        
        options = doc.SearchObject("Options")     # This is where userdata located
        
        if options is None:
            print "main controls not found"
            return
        
        children = node.GetChildren()
        count = len(children)
        
        # Create and initialize user data container for an integer for the children
        bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_LONG)
        bc.SetString(c4d.DESC_NAME, node.GetName())
        bc.SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_CYCLE)
        bc.SetInt32(c4d.DESC_MIN, 0)
        bc.SetInt32(c4d.DESC_MAX, count-1)
        
        # Create a container for the dropdown cycle values
        cycle = c4d.BaseContainer()
        
        for index in range(0, count) :
            child = children[index]
            cycle.SetString(index, child.GetName())
        
        # Set cycle values container
        bc.SetContainer(c4d.DESC_CYCLE, cycle)
        
        # Set container for children user data cycle parameter
        options.SetUserDataContainer([c4d.ID_USERDATA, 1], bc)
        
        names = ""
    


  • On 20/06/2015 at 12:49, xxxxxxxx wrote:

    Hello,
    Thanks for the answer, it worked:)

    But now I have realized that my specific userdata should be in another userdata group. 
    It changes default Userdata group automatically. But I could not find how to access another userdata group..
    Really searched on net but could not find any info. As I said I'm just a beginner:)

    Again my scene;
    https://www.dropbox.com/s/etmln6e7esvtnp1/modify_userdata_another_group.c4d?dl=0

    😢



  • On 17/07/2015 at 02:48, xxxxxxxx wrote:

    Hi,

    Sorry for the late reply.

    To set the parent group for a user data assign DESC_PARENTGROUP. This value in the description container accepts a DescID and has to be setup like this:

    parentGroup = c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA), c4d.DescLevel(theGroupID, c4d.DTYPE_GROUP, 0))
    bc.SetData(c4d.DESC_PARENTGROUP, parentGroup)
    

    theGroupID is the ID number for the group (4 in your example scene).



  • On 17/07/2015 at 05:52, xxxxxxxx wrote:

    Hi Yannick,
    Thank you for your answer;
    (Sorry If I am asking so many question, trying to learn...)

    What I am doing wrong? I've added your last strings but still it's not working.

    Script By Yannick Puech

    import c4d
    from c4d import gui
    from c4d import documents

    def GetChildren(Object) :
        global names
        
        options = doc.SearchObject("Options")     # This is where userdata located
        
        if options is None:
            print "main controls not found"
            return
        
        children = Object.GetChildren()
        count = len(children)
        
        # Create and initialize user data container for an integer for the children
        bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_LONG)
        bc.SetString(c4d.DESC_NAME, Object.GetName())
        bc.SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_CYCLE)
        bc.SetInt32(c4d.DESC_MIN, 0)
        bc.SetInt32(c4d.DESC_MAX, count-1)
        parentGroup = c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA), c4d.DescLevel(4, c4d.DTYPE_GROUP, 0))
        bc.SetData(c4d.DESC_PARENTGROUP, parentGroup)
        # Create a container for the dropdown cycle values
        cycle = c4d.BaseContainer()
        
        for index in range(0, count) :
            child = children[index]
            cycle.SetString(index, child.GetName())
        
        # Set cycle values container
        bc.SetContainer(c4d.DESC_CYCLE, cycle)
        
        # Set container for children user data cycle parameter
        options.SetUserDataContainer([c4d.ID_USERDATA, 1], bc)
        
        names = ""
        
    def main() :
        GetChildren(Object)



  • On 17/07/2015 at 06:17, xxxxxxxx wrote:

    Hi I think I've done finally:)
    Thanks a lot Yannick, I have placed it inside Python Tag.
    And if anyone intrested ;

    Script By Yannick Puech

    import c4d
    from c4d import gui
    from c4d import documents

    def GetChildren() :
        global names
        profiles = doc.SearchObject("Profiles")   # Null name contains children objects
        options = doc.SearchObject("Options")     # This is where userdata located   
        if options is None:
            print "main controls not found"
            return
        
        children = profiles.GetChildren()
        count = len(children)
        
        # Create and initialize user data container for an integer for the children
        
        bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_LONG)
        
        bc.SetString(c4d.DESC_NAME, profiles.GetName())
        bc.SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_CYCLE)
        bc.SetInt32(c4d.DESC_MIN, 0)
        bc.SetInt32(c4d.DESC_MAX, count-1)
        parentGroup = c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA), c4d.DescLevel(4, c4d.DTYPE_GROUP, 0))# 4 is my secondary Group ID
        bc.SetData(c4d.DESC_PARENTGROUP, parentGroup)
        # Create a container for the dropdown cycle values
        cycle = c4d.BaseContainer()
        for index in range(0, count) :
            child = children[index]
            cycle.SetString(index, child.GetName())
        # Set cycle values container
        bc.SetContainer(c4d.DESC_CYCLE, cycle)
        # Set container for children user data cycle parameter
        options.SetUserDataContainer([c4d.ID_USERDATA, 1], bc)
        
        names = ""
        
    def main() :
        
        GetChildren()



  • On 17/07/2015 at 06:22, xxxxxxxx wrote:

    Btw I've noticed that as I paste this code in my real project It deletes my current other options userdata. 
    Is there a way to add or modify directly without deleting or recreating other userdatas ?

    In my case my group ID is 2 and drop down list should be in userdata with ID 13 for example.

    This is last step Yannick, please do me a favor last time:)))

    Thanks a lot again.



  • On 17/07/2015 at 07:28, xxxxxxxx wrote:

    To add a user data use BaseList2D.AddUserData().
    To modify a user data retrieve its description container with BaseList2D.GetUserDataContainer() and set it back with BaseList2D.SetUserDataContainer().



  • On 17/07/2015 at 08:44, xxxxxxxx wrote:

    I'm again confused, according to my previous example I tried to add getuserdatacontainer and setuserdatacontainer...But it's still not working...
    (In this example my group ID is 1 and drop down cycle UD id is 13, I only need to modify it, it already exists...Sorry again as a beginner it's so confusing...)

    Script By Yannick Puech

    import c4d
    from c4d import gui
    from c4d import documents

    def GetChildren() :
        global names
        profiles = doc.SearchObject("Profiles")   # Null name contains children objects
        options = doc.SearchObject("Options")     # This is where userdata located   
        if options is None:
            print "main controls not found"
            return
        
        children = profiles.GetChildren()
        count = len(children)
        
        # Create and initialize user data container for an integer for the children
        bc = options.GetUserDataContainer()
        bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_LONG)
        
        bc.SetString(c4d.DESC_NAME, profiles.GetName())
        bc.SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_CYCLE)
        bc.SetInt32(c4d.DESC_MIN, 0)
        bc.SetInt32(c4d.DESC_MAX, count-1)
        parentGroup = c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA), c4d.DescLevel(1, c4d.DTYPE_GROUP, 0))
        bc.SetData(c4d.DESC_PARENTGROUP, parentGroup)
        
        cycle = c4d.BaseContainer()
        for index in range(0, count) :
            child = children[index]
            cycle.SetString(index, child.GetName())
        
        bc.SetContainer(c4d.DESC_CYCLE, cycle)
        # Set container for children user data cycle parameter
        options.SetUserDataContainer([c4d.ID_USERDATA,13], bc)
        
        names = ""
        
    def main() :
        
        GetChildren()


Log in to reply