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()