Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Change an attribute from a dialogue plug-in

    Cinema 4D SDK
    r20 python
    3
    12
    1.2k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ferdinandF
      ferdinand
      last edited by

      Hi,

      have you tried invoking c4d.EventAdd() orobject.Message(c4d.MSG_UPDATE) after you changed the name?

      Cheers,
      zipit

      MAXON SDK Specialist
      developers.maxon.net

      1 Reply Last reply Reply Quote 1
      • B
        bentraje
        last edited by

        @zipit

        Thanks for the response.
        Yes, I tried both commands but it does not work as expected (i.e. typing something in the plug-in does not change the object)

        Also I think c4d.EventAdd() is only necessary on script. And the Message I think only works if you are going to modify a parameter specific to an object (say a point). Correct me if I'm wrong.

        1 Reply Last reply Reply Quote 0
        • S
          s_bach
          last edited by

          Hello,

          c4d.EventAdd() is always needed when one changes the active document in the context of some user interaction. This includes user interaction in a GeDialog (Core Messages Manual).

          Also, don't forget to call c4d.StopAllThreads() when you edit the document asynchronously (BaseDocument Manual).

          You should react to user interaction in your GeDialog's Command() function. Can you share the complete code of your Command() function?

          best wishes,
          Sebastian

          MAXON SDK Specialist

          Development Blog, MAXON Registered Developer

          1 Reply Last reply Reply Quote 1
          • B
            bentraje
            last edited by

            @s_bach

            Sure sure. There is not much in the Command function except the return True.
            Here is the working code so far (it 's the same code as I previously asked in my previous threads.

            Thank you for looking at it.

            import c4d
            import os
            from c4d import gui, plugins, bitmaps, utils, documents
            
            PLUGIN_ID   = 1811321
            
            class MyDialog(gui.GeDialog):
            
                def __init__(self):
                    # Be sure that we have the object list before building the UI
                    # as InitValues is called after CreateLayout()
                    self.objectsList = []
                    self.GetAllObjects()
                    self.object_count = len(self.objectsList)
            
            
                def InitValues(self):
                    # Use to Init and in Case of an Update needed.
                    self.objectsList = []
                    self.GetAllObjects()
                    self.object_count = len(self.objectsList)
                    self.Update()
                    return True
            
                def GetNextObject(self, op ):
                    # use a non-recursive method to iterate the hierarchy
                    # [URL-REMOVED]
                    # allow to not hit the recursive stack limit.
            
                    if not op:
                        return None
            
                    if op.GetDown():
                        return op.GetDown()
            
                    while not op.GetNext() and op.GetUp():
                        op = op.GetUp()
            
                    return op.GetNext()
            
                def GetAllObjects(self):
            
                    doc = c4d.documents.GetActiveDocument()
                    op = doc.GetFirstObject()
            
                    self.objectsList = []
            
                    while op:
                        self.objectsList.append(op)
                        op = self.GetNextObject(op)
            
                def Update(self): # NEW CODE
            
                    if self.object_count == 0:
                        self.LayoutFlushGroup(1001)
                        self.AddStaticText(0, c4d.BFH_CENTER, name="There are no objects in the scene")
                        self.LayoutChanged(1001)
            
                    if self.object_count > 0 :
                        self.LayoutFlushGroup(1001)
            
                        self.AddStaticText(0, 1, name="Name")
                        self.AddStaticText(0, 0, name="Enable")
                        self.AddStaticText(0, 0, name="Xray")
            
                        self.AddSeparatorV(0)
                        self.AddSeparatorV(0)
                        self.AddSeparatorV(0)
            
                        for idx, object in enumerate(self.objectsList): # where the glitch happens
            
                            text_ID = 100000 + idx
                            enable_ID = 200000 + idx
                            xray_ID = 300000 + idx
            
                            self.AddEditText(text_ID, flags=c4d.BFH_LEFT, initw=200, editflags=c4d.EDITTEXT_HELPTEXT)
                            self.AddCheckbox(enable_ID, flags=c4d.BFH_LEFT, initw=20, inith=10, name="Enable")
                            self.AddCheckbox(xray_ID, flags=c4d.BFH_LEFT, initw=20, inith=10, name="Xray")
            
            
            
                            self.SetString(text_ID, value=object.GetName())
                            self.SetInt32(enable_ID, value=object[c4d.ID_BASEOBJECT_GENERATOR_FLAG])
                            self.SetInt32(xray_ID, value=object[c4d.ID_BASEOBJECT_XRAY])
            
                            newString = self.GetString(text_ID)
                            object.SetName(newString)
            
                            object.Message(c4d.MSG_UPDATE)
            
                        self.LayoutChanged(1001)
            
                def CreateLayout(self):
            
            
                    print "nombre d'objet ", self.object_count
                    self.GroupBegin(id=1001, flags=c4d.BFH_FIT, cols=3, rows=20, title="Rigging")
            
                    self.GroupEnd()
            
                    self.Update()
            
                    return True
            
                def Command(self, id, msg):
            
                    return True
            
            
                def CoreMessage(self, id, msg):
            
                    if id == c4d.EVMSG_CHANGE:
            
                        self.InitValues()
            
                    return True
            
            class MyMenuPlugin(plugins.CommandData):
            
            
                dialog = None
                def Execute(self, doc):
            
                    if self.dialog is None:
                        self.dialog = MyDialog()
            
                    return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=200, defaulth=150, xpos=-1, ypos=-1)
            
            if __name__ == "__main__":
            
                plugins.RegisterCommandPlugin(PLUGIN_ID, "test_dynamic_update",0, None, "test_dynamic_update", MyMenuPlugin())
            

            [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

            1 Reply Last reply Reply Quote 0
            • S
              s_bach
              last edited by s_bach

              Hello,

              as I said above, you have to handle user interaction in the dialog's Command() function. The function if called when the user interacts with the dialog's gadgets. Something like this:

              def Command(self, id, msg):
              
                  if id >= 100000 and id < 200000:
                      idx = id - 100000
              
                      newString = self.GetString(id)
              
                      obj = self.objectsList[idx]
                      if obj is not None:
                          c4d.StopAllThreads()
                          obj.SetName(newString)
                          c4d.EventAdd()
              
                      
              
                  return c4d.gui.GeDialog.Command(self, id, msg)
                  
              

              best wishes,
              Sebastian

              MAXON SDK Specialist

              Development Blog, MAXON Registered Developer

              1 Reply Last reply Reply Quote 1
              • B
                bentraje
                last edited by

                @s_bach

                Thanks for the response. I used the code. It works but I'm unable to type anything other than a single stroke. I think the c4d.EventAdd updates so fast.
                You can check the illustration of the problem here:
                https://www.dropbox.com/s/klbljd5w3uvak2t/c4d137_change_name_plug_in_02.mp4?dl=0

                I tried removing the c4d.EventAdd(). It lets me type something but it only updates when I click outside the plug-in.

                Is there a possibility of both worlds? Update only when I move to a next field (i.e. tab) perhaps?

                1 Reply Last reply Reply Quote 0
                • S
                  s_bach
                  last edited by

                  Hello,

                  you have to call EventAdd() to inform Cinema that you have changed something.

                  But in your code, you call your Update() function after a EVMSG_CHANGE message. In your Update() function, you delete and rebuild your UI, thus you loose the focus on the current UI gadget.

                  You must find a way to either not call Update() after you edit the name of the object or to restore the focus on the newly created UI.

                  best wishes,
                  Sebastian

                  MAXON SDK Specialist

                  Development Blog, MAXON Registered Developer

                  1 Reply Last reply Reply Quote 1
                  • S
                    s_bach
                    last edited by

                    Alternatively, you can check if the ENTER key way pressed and only update when this is the case (the user finished entering the string, see Interaction with Gadgets).

                    # get state of the "Enter" key.
                    state = c4d.BaseContainer()
                    res = c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD, c4d.KEY_ENTER, state)
                    
                    if res:
                      if state[c4d.BFM_INPUT_VALUE] != 1:
                        return False
                    
                      idx = id - 100000
                    
                      newString = self.GetString(id)
                    
                      obj = self.objectsList[idx]
                      if obj is not None:
                          c4d.StopAllThreads()
                          obj.SetName(newString)
                          c4d.EventAdd()
                    

                    This way, the dialog would behave similiar to the Attribute Manager.

                    best wishes,
                    Sebastian

                    MAXON SDK Specialist

                    Development Blog, MAXON Registered Developer

                    1 Reply Last reply Reply Quote 1
                    • B
                      bentraje
                      last edited by

                      Hi @s_bach

                      Thanks for the response. I change the askChannel to c4d.KEY_TAB.
                      It works as expected, but it doesn't continue to the next line when I hit tab. It goes back to the first line.

                      You can see an illustration of the problem here:
                      https://www.dropbox.com/s/wwf72tkc0pmar96/c4d137_change_name_plug_in_03_move_fifth.mp4?dl=0

                      I was expecting when I hit Tab from the fourth line it would continue to all the parameters until it reaches to the fifth line.

                      Is this possible? Or is this a limitation on the GetInputState?

                      1 Reply Last reply Reply Quote 0
                      • S
                        s_bach
                        last edited by

                        Hello,

                        as I said above: you rebuild your UI after each EVMSG_CHANGE. Thus, you loose the focus of your UI elements (since they are destroyed and rebuilt).

                        You have to find a way to avoid that unnecessary rebuild of your layout after user interaction in your dialog.

                        best wishes,
                        Sebastian

                        MAXON SDK Specialist

                        Development Blog, MAXON Registered Developer

                        1 Reply Last reply Reply Quote 1
                        • B
                          bentraje
                          last edited by

                          @s_bach

                          RE: You have to find a way to avoid that unnecessary rebuild of your layout after user interaction in your dialog.
                          I'm not really sure how to do that. Since I just butchered the code from a sample plug-in.
                          That will probably a problem for another thread.

                          Anyway, it's functional at the moment. I'll settle for this.

                          Thanks again and sorry for the trouble.

                          Will close the thread now.

                          Have a great day ahead!

                          1 Reply Last reply Reply Quote 0
                          • First post
                            Last post