Getting UserData ID#



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 04/12/2012 at 19:48, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   13 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Can anyone tell me how to get the ID# for UserData items?
    I need to get the ID# for each UD item that's displayed in the UD manager.

    There's a Find() function in the SDK that might do it. But it returns a type that I can't use.
    If I could convert this to an int, or a LONG type, it might do the trick.

        BaseObject *obj = doc->GetActiveObject();           //The object the UD is attached to  
      
      DynamicDescription *ud = obj->GetDynamicDescription();  
      for(int i=0; i<4; i++)  
      {  
          ud->Find(i);   //<--This is useless to me unless I can somehow convert it to a LONG or an int type  
      }
    

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 04/12/2012 at 20:46, xxxxxxxx wrote:

    Doh!
    Why is it that I can spend hours on a problem and not get anywhere.
    Then after I ask for help. I figure out the solution? 😊

    Instead of deleting the thread. I'll post the code in case anyone else needs it:

        BaseObject *obj = doc->GetActiveObject();           //The object the UD is attached to  
      
      if(obj)  
       {           
        DynamicDescription *dd = obj->GetDynamicDescription();  
        if(dd)  
         {  
          DescID dscID;  
          const BaseContainer *bc;  
          void *dscHnd = dd->BrowseInit();                //Initialize the Browse function  
          while(dd->BrowseGetNext(dscHnd, &dscID, &bc))   //Loop through the UserData entries  
            {       
              LONG index = dscID[1].id;                   //Get the ID# of each UD item                  
              GePrint(LongToString(index));     
            }  
          dd->BrowseFree(dscHnd);                  //Let go of the browse function..Free it's memory  
         }  
       }
    

    I would like to know how to use the Find() function though.
    I'm still curious about that one.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 06/12/2012 at 03:33, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I would like to know how to use the Find() function though.
    I'm still curious about that one.

    DynamicDescription::Find() needs a description ID, not an index. It's the fastest way to get a user data settings if you know its ID.
    But if you don't know it, the code you've posted is the way to go (browsing the user data).



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 06/12/2012 at 10:08, xxxxxxxx wrote:

    Could you possibly post an example of using it?
    I'm stumped how to use this thing.

    I think I'm setting it up properly. But there's no way I see to actually use it?

        BaseObject *obj = doc->GetActiveObject();   
      DynamicDescription *dd = obj->GetDynamicDescription();     
      
      //Get the UD entry with ID# 2  
      LONG gizmo = 2;  
      DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, DESCFLAGS_GET_0), DescLevel(gizmo, DTYPE_REAL, 0));  
      dd->Find(udEntry);  //<--What do I do with this?
    

    -It won't let me assign a variable to it of any type so I can use it
    -It doesn't appear to do anything like select the user data

    Also:
    I'm having a hard time checking a UD's type when I'm grabbing a specific one by it's ID#.
    This code technically works...But only after I manually change the value in UD#2 first.
    In other words. I have to manually give UD#2 focus with my mouse for this code to work. Which is very, very bad!

        BaseObject *obj = doc->GetActiveObject();   
      DynamicDescription *dd = obj->GetDynamicDescription();     
      
      //Get the UD entry with ID# 2  
      LONG gizmo = 2;  
      DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, DESCFLAGS_GET_0), DescLevel(gizmo, DTYPE_REAL, 0));  
      
      GeData d;  
      obj->GetParameter(udEntry, d, DESCFLAGS_GET_0);  
      
      if(d.GetType() != DTYPE_REAL)  
      {   
          GePrint("Wrong Data type");  
      }  
      else  
      {  
          obj->SetParameter(DescID(udEntry), GeData(.5), DESCFLAGS_SET_0);  
      }
    

    Maybe UserData would be is a good subject to cover in the new programming blog?

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 06/12/2012 at 10:55, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    -It won't let me assign a variable to it of any type so I can use it
    -It doesn't appear to do anything like select the user data

    DynamicDescription::Find() returns a const BaseContainer* (i.e. read-only) so you cannot modify it.
    The returned container contains the description information for the passed ID (see class Description in the C++ docs).

    Originally posted by xxxxxxxx

    I'm having a hard time checking a UD's type when I'm grabbing a specific one by it's ID#.
    This code technically works...But only after I manually change the value in UD#2 first.
    In other words. I have to manually give UD#2 focus with my mouse for this code to work. Which is very, very bad!

    I think you should just call EventAdd() after setting the parameter, to tell something has changed.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 06/12/2012 at 13:36, xxxxxxxx wrote:

    I know it returns a const BaseContainer. But I cannot do anything with it.
    I usually have no problems getting data from containers. But this thing is a different animal.
    I can't read any data from it in this form: dd->Find(udEntry);
    I need a way to read the data from that line of code.

    Using EventAdd() didn't work.
    This is just a wild guess on my part.
    But the problem seems to be that when we add user data. C4D doesn't see it until we actually click on it with the mouse. And that's why my container named "d" is returning zero, instead the type value, until I manually click and edit that UD entry.

        //Get the UD entry with ID# 2  
      LONG gizmo = 2;  
      DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, DESCFLAGS_GET_0), DescLevel(gizmo));  
      dd->Find(udEntry);  
        
      GeData d;  
      obj->GetParameter(udEntry, d, DESCFLAGS_GET_0);  
      GePrint(LongToString(d.GetType()));      //<--Returns 0 until I select the UD and change it's value  
                                               //Once I do that..It returns the proper type value for the UD
    

    I do have another code snippet that loops through the UD and gets the types. And it that one works properly. But... it uses a BaseContainer (not GetParameter) and the BrowseGetNext() function.
    What If I only want to make a small change to one specific user data item?
    Do I have to loop through all of them. Every single time. Because that's the only way to get their current values?

    Something appears to be going on inside of the BrowseGetNext() function that tells C4D what the current values are for each UD entry.
    I need to know what that magic code is inside that function that does this so I don't have to loop through them all, or manually give the specific UD focus by editing it, just to make a small change to only one of the UD items with code.

    BTW:
    If you're wondering what I'm doing. I'm adding, removing, and changing user data on objects and tags from a GeDialog plugin.
    Sort of controlling UD by remote control.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 07/12/2012 at 03:04, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I know it returns a const BaseContainer. But I cannot do anything with it. 
    I usually have no problems getting data from containers. But this thing is a different animal.
    I can't read any data from it in this form: dd->Find(udEntry);
    I need a way to read the data from that line of code.

    You can only call the const methods on the returned container:

    const BaseContainer *udDescription = dynDesc->Find(udID);
    if (udDescription==NULL) return FALSE;
      
    GePrint(udDescription->GetString(DESC_NAME));
    
    DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, DESCFLAGS_GET_0), DescLevel(gizmo));
    

    I think the description ID should be declared as:

    DescID udID(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), DescLevel(gizmo, DTYPE_REAL, 0));
    

    Originally posted by xxxxxxxx

    Using EventAdd() didn't work.
    This is just a wild guess on my part.
    But the problem seems to be that when we add user data. C4D doesn't see it until we actually click on it with the mouse. And that's why my container named "d" is returning zero, instead the type value, until I manually click and edit that UD entry.

    I can't reproduce this behavior. I created a user data with the UI (without clicking it) and also tried with the SDK, here's my code:

    BaseObject *op = doc->GetActiveObject();
    if (op==NULL) return FALSE;
      
    GeData data;
    DescID udID(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), DescLevel(1, DTYPE_REAL, 0));
      
    DynamicDescription *dynDesc = op->GetDynamicDescription();
    if (dynDesc==NULL) return FALSE;
      
    BaseContainer udSettings;
    if (!dynDesc->FillDefaultContainer(udSettings, DTYPE_REAL, "Name"))
        return FALSE;
      
    dynDesc->Set(udID, udSettings, NULL);
      
    if (op->GetParameter(udID, data, DESCFLAGS_GET_0))
        GePrint(LongToString(data.GetType()));
      
    const BaseContainer *udDesc = dynDesc->Find(udID);
    if (udDesc==NULL) return FALSE;
      
    GePrint(udDesc->GetString(DESC_NAME));
    

    Originally posted by xxxxxxxx

    I do have another code snippet that loops through the UD and gets the types. And it that one works properly. But... it uses a BaseContainer (not GetParameter) and the BrowseGetNext() function.
    What If I only want to make a small change to one specific user data item?
    Do I have to loop through all of them. Every single time. Because that's the only way to get their current values?

    Looping through the dynamic description parameters with BrowseGetNext() is the only way to modify the description of a user data.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 07/12/2012 at 09:00, xxxxxxxx wrote:

    Thanks a lot for the help Yannick.
    I think I understand how to use that Find() method now.

    As I stumble around trying to learn how to use the things in the SDK. I often do things that were never intended to be done with it.
    One of the things I found in my experiments is that there is no support for targeting a specific UD entry and getting it's type without using that special loop function.
    That's why I used:
    DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, DESCFLAGS_GET_0), DescLevel(1));
    Instead of
    DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, DESCFLAGS_GET_0), DescLevel(1), DTYPE_REAL,DESCFLAGS_GET_0);

    If you don't know the type of a specific UD entry that you are targeting. And want to find the type by asking for the type with GetType(). Then you have no idea which type ID to include at the end of that line of code. Which is why I left that part blank.
    But as it turns out. Including the type is a very important part of this code. And when you leave it out. Strange things happen.
    In my case. What happened was I would not get a return value from the UD entry I targeted until I physically clicked on it.

    Although it looks like a bug. I understand that it's really just a case of the user(me) doing something that was never supposed to be done with the code.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 10/12/2012 at 03:26, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, DESCFLAGS_GET_ 0), DescLevel(1, DTYPE_REAL, DESCFLAGS_GET_0 ));

    I still don't understand why do you still use DESCFLAGS_GET_0 as t_creator value for DescLevel constructor. It's usually set to 0 and DESCFLAGS_GET_0 is only meant to be used with C4DAtom::GetParameter().

    Originally posted by xxxxxxxx

    If you don't know the type of a specific UD entry that you are targeting. And want to find the type by asking for the type with GetType(). Then you have no idea which type ID to include at the end of that line of code. Which is why I left that part blank.
    But as it turns out. Including the type is a very important part of this code.

    If you don't know the type of a description ID, the only way is to loop trough the standard/dynamic container description (C4DAtom::GetDescription() and C4DAtom::GetDynamicDescription()).

    Originally posted by xxxxxxxx

    And when you leave it out. Strange things happen.
    In my case. What happened was I would not get a return value from the UD entry I targeted until I physically clicked on it.

    Although it looks like a bug. I understand that it's really just a case of the user(me) doing something that was never supposed to be done with the code.

    What version of CINEMA are you using? I can't reproduce this strange behavior.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 10/12/2012 at 08:27, xxxxxxxx wrote:

    The only reason I used  DESCFLAGS_GET_0 in my code there was because the only forum posts I could find about user data was for R12. And I'm testing this in R13.
    R13 changed from using 0 to DESCFLAGS_GET_0. And I probably just converted that one from zero out of habit due to the errors I was getting when trying to use the forum code.

    Since you could not reproduce the same results. I created a brand new GeDialog plugin with nothing in it but the code I posted. And it seems to work properly for me now too.
    I don't know why it wasn't working in my other plugin. I must have done something strange in that other plugin to cause this behavior.

    Thanks a lot for the help.
    I have a much better understanding about the C++ user data code now.

    -ScottA


Log in to reply