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

    AddEditNumberArrows Stops Working on Keyed objects

    Cinema 4D SDK
    r21 python
    2
    12
    1.6k
    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.
    • B
      bentraje
      last edited by

      Hi @m_magalhaes

      Thanks for the response.
      I tried your code. It does work with the keyed object.
      The problem is it overrides the previous values.
      For instance, Frame 0: Value 0. Then key somethin in Frame 12: Value 20
      The Frame 0 now has Value 20

      You can see the problem here:
      https://www.dropbox.com/s/fn7b1ti7s4f8sk9/c4d216_addeditnumberarrows_stops_working_on_keyed_object02.mp4?dl=0

      I initially thought it was just Activating the track again. So I added that snippet but I still have the same problem. You can check the working code here:

      import c4d
      import sys
      from c4d import bitmaps, documents, gui, plugins, threading, utils
      
      
      class MyDialog(c4d.gui.GeDialog):
      
          def __init__(self):
              doc = c4d.documents.GetActiveDocument()
              self.finger_B_01_L_con = doc.SearchObject('Cylinder')
              
          def DesactivateTracks(self, op):
              # Retrieves the tracks.
              tracks = op.GetCTracks()
              # Track list that we want to desactivate.
              trackListToDIsable = [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE]
              for track in tracks:
                  did = track.GetDescriptionID()
          
                  # If the Parameter ID of the current CTracks is not on the trackListToDIsable we go to the next one.
                  if not did[0].id in trackListToDIsable:
                      continue
          
                  track.SetBit(c4d.BIT_ANIM_OFF)
                  
          def ActivateTracks(self, op):
              # Retrieves the tracks.
              tracks = op.GetCTracks()
              # Track list that we want to desactivate.
              trackListToDIsable = [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE]
              for track in tracks:
                  did = track.GetDescriptionID()
          
                  # If the Parameter ID of the current CTracks is not on the trackListToDIsable we go to the next one.
                  if not did[0].id in trackListToDIsable:
                      continue
          
                  track.SetBit(c4d.BIT_ACTIVE)
      
          def CreateLayout(self):
              self.AddEditNumberArrows(id=404040, flags=c4d.BFH_LEFT, initw=100, inith=0)
              return True
      
          def InitValues(self):
              val = self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z]
              self.SetDegree(404040, val, min=-180, max=180, step=1, tristate=False)
              return True
      
      
          def Message(self, msg, result):
      
              if msg.GetId() == c4d.BFM_ACTION:
                  
                  self.DesactivateTracks(self.finger_B_01_L_con)
                  self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = self.GetFloat(404040)
                  self.ActivateTracks(self.finger_B_01_L_con)
      
                  c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW | c4d.DRAWFLAGS_NO_THREAD | c4d.DRAWFLAGS_NO_REDUCTION | c4d.DRAWFLAGS_STATICBREAK)
                      
      
              if msg.GetId() == c4d.BFM_INTERACTEND:
      
                  self.InitValues()
                  return True
      
              return c4d.gui.GeDialog.Message(self, msg, result)
      
          def Command (self, id, msg):
      
              return True
      
      if __name__ == "__main__":
          dlg = MyDialog()
          dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC)
      
      1 Reply Last reply Reply Quote 0
      • ManuelM
        Manuel
        last edited by Manuel

        hello,

        • opening a DLG_TYPE_ASYNC shouldn't be done in a script, you should create a CommandeDataPlugin to store your GeDialog
        • your ActivateTracks isn't right, track.SetBit(c4d.BIT_ACTIVE) is not the right command to "activate" a track. In that case, activate mean "selected" Have a look at this page for more information about BITs. Because you have set the bit to BIT_ANIM_OFF you have to delete that bit using DelBit
        • In your vidéo, the yellow point mean "the field value is not the same as the track value" That also mean your track is not enabled.

        Your script, as you are trying to do it, will never work. Disabling the track, change the value, reactivate the track = the object will go back to the defined value of the track. So you have never the change to create a keyframe with the right value.

        Get a look at those examples if you want to add keys to your tracks (or manage tracks).

        there's this one in particular that could help you.

        But maybe you can have a look at TranslateDescID and we have an example here

        This could allow to create a tool (instead of a gedialog) where you can route your description value to another parameter of another object. So the track and keys will not be created for your tools'parameters, but on your target's parameters. (maybe it's not clear)

        Cheers,
        Manuel.

        `

        MAXON SDK Specialist

        MAXON Registered Developer

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

          @m_magalhaes

          Thanks for the response.
          So, I guess the workflow above would be to set the keys manually.

          Is there a way I can leverage the "Auto-Key" function?
          I don't mind if its hack. I just want it to work and just want to animate for now.

          So basically, change the value and have the auto-key handled the keying much the same way when changing value using the default UI (i.e. not using script/plugin).

          1 Reply Last reply Reply Quote 0
          • ManuelM
            Manuel
            last edited by

            hello,

            see this thread about using the autokey

            Let me know if you have any questions.

            Cheers,
            Manuel

            MAXON SDK Specialist

            MAXON Registered Developer

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

              Hi @m_magalhaes

              Thanks for the response.

              RE: Your script, as you are trying to do it, will never work. Disabling the track, change the value, reactivate the track
              Oh okay. The "reactivation part" was just my hunch since you deactivate it first. I was thinking to reactivate it again.

              That said, I tried doing only Disabling Track and Change Value but the result is still the same (i.e. It does work with the keyed object. The problem is it overrides the previous values. )

              RE: your ActivateTracks isn't right, track.SetBit(c4d.BIT_ACTIVE) is not the right command to "activate" a track.
              So I guess this part is irrelevant since I don't need to activate/reactive it?

              RE: this thread about using the autokey

              I tried the autokey with the doc.AutoKey and even with the doc.Recordbut I still get the same result ( .e. It does work with the keyed object. The problem is it overrides the previous values.)

              Here is the working code in a plugin form as you suggested:
              It only works on the object named "Cylinder" same as before:

              import c4d
              import sys
              from c4d import bitmaps, documents, gui, plugins, threading, utils
              
              
              PLUGIN_ID   = 18113999  # Just test ID. Not for production.
              class MyDialog(c4d.gui.GeDialog):
              
                  def __init__(self):
                      self.doc = c4d.documents.GetActiveDocument()
                      self.finger_B_01_L_con = self.doc.SearchObject('Cylinder')
                      
                  def DesactivateTracks(self, op):
                      # Retrieves the tracks.
                      tracks = op.GetCTracks()
                      # Track list that we want to desactivate.
                      trackListToDIsable = [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE]
                      for track in tracks:
                          did = track.GetDescriptionID()
                  
                          # If the Parameter ID of the current CTracks is not on the trackListToDIsable we go to the next one.
                          if not did[0].id in trackListToDIsable:
                              continue
                  
                          track.SetBit(c4d.BIT_ANIM_OFF)
                          
                  def ActivateTracks(self, op):
                      # Retrieves the tracks.
                      tracks = op.GetCTracks()
                      # Track list that we want to desactivate.
                      trackListToDIsable = [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE]
                      for track in tracks:
                          did = track.GetDescriptionID()
                  
                          # If the Parameter ID of the current CTracks is not on the trackListToDIsable we go to the next one.
                          if not did[0].id in trackListToDIsable:
                              continue
                  
                          track.SetBit(c4d.BIT_ACTIVE)
              
                  def CreateLayout(self):
                      self.AddEditNumberArrows(id=404040, flags=c4d.BFH_LEFT, initw=100, inith=0)
                      return True
              
                  def InitValues(self):
                      val = self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z]
                      self.SetDegree(404040, val, min=-180, max=180, step=1, tristate=False)
                      return True
              
              
                  def Message(self, msg, result):
              
                      if msg.GetId() == c4d.BFM_ACTION:
              
                          ID_AUTOKEYING_COMMAND = 12425
                      
                          previousAutokeyEnableState = c4d.IsCommandChecked(ID_AUTOKEYING_COMMAND)
                          if not previousAutokeyEnableState:
                              c4d.CallCommand(ID_AUTOKEYING_COMMAND)
              
                                  
                          self.DesactivateTracks(self.finger_B_01_L_con)
                          self.doc.StartUndo()
                          self.doc.AddUndo(c4d.UNDOTYPE_CHANGE, self.finger_B_01_L_con)
                          undoObj = self.doc.GetUndoPtr()
                          self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = self.GetFloat(404040)
                          #self.ActivateTracks(self.finger_B_01_L_con)
                          
                          self.doc.AutoKey(self.finger_B_01_L_con, undoObj, False, True, True, True, True, True)
                          self.doc.Record()
              
                          c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW | c4d.DRAWFLAGS_NO_THREAD | c4d.DRAWFLAGS_NO_REDUCTION | c4d.DRAWFLAGS_STATICBREAK)        
              
                          self.doc.EndUndo()
              
                          if not previousAutokeyEnableState:
                              c4d.CallCommand(ID_AUTOKEYING_COMMAND)
                              
              
              
                      if msg.GetId() == c4d.BFM_INTERACTEND:      
              
                          self.InitValues()
                          return True
              
                      return c4d.gui.GeDialog.Message(self, msg, result)
              
                  def Command (self, id, msg):
              
                      return True
              
              class MyMenuPlugin(plugins.CommandData):
                  dialog = None
                  def Execute(self, doc):
                  # create the dialog
                     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)
                  def RestoreLayout(self, sec_ref):
                  # manage the dialog
                     if self.dialog is None:
                        self.dialog = MyDialog()
                     return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)
              if __name__ == "__main__":
                  okyn = plugins.RegisterCommandPlugin(PLUGIN_ID, "Key Objects Interactively",0, None, "Key Objects Interactively", MyMenuPlugin())
                  if (okyn):
                      print "Key Objects Interactively"
              
              1 Reply Last reply Reply Quote 0
              • ManuelM
                Manuel
                last edited by Manuel

                @bentraje said in AddEditNumberArrows Stops Working on Keyed objects:

                It does work with the keyed object. The problem is it overrides the previous values.)

                sorry i wasn't clear with what i said (or i can't reproduce the issue) :

                In your vidéo, the yellow point mean "the field value is not the same as the track value" That also mean your track is not enabled.

                In our help you will find what colors mean and full circle or not.

                the value of the parameter is -2° but the point is yellow and full, that mean the track have a key at that frame but the value isn't the same as the parameter.
                5aff93fb-a2a8-4a54-aea2-c289d817c5fb-image.png

                Your track is deactivate. But the key value is still there
                3e2bedf9-bab8-4e21-87b1-40a7ad1e745d-image.png

                Cheers,
                Manuel

                MAXON SDK Specialist

                MAXON Registered Developer

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

                  @m_magalhaes

                  Thanks for the response.

                  Can I clear the previous queries?

                  1. So is it correct to DeactiveTrack, Change Value and not Activate it again?
                    or Do I have to DeactiveTrack, Change Value and ActivateTrack?
                  2. I understand what yellow circle means which is my problem. I thought the doc.AutoKey or doc.Record will handle that, but it didn't.

                  Overall, I'm confused about the overall workflow.
                  So far what I understand is two methods:

                  1. Manually:
                    A) Deactivate Track
                    B) Change Value
                    C) Key Value
                    D) Activate Track
                  2. Automatically.
                    A) Change Value
                    B) Dodoc.Autokey and doc.Record

                  I just want the second want because it is easier. Is this possible?

                  1 Reply Last reply Reply Quote 0
                  • ManuelM
                    Manuel
                    last edited by

                    hello,

                    With the second method (automatically) you will not be able to see the change while you are dragging the value of the parameter because the track will erase what you are doing.

                    I've modified a bit your code (specially now creating the key is on Command and not on Message).
                    I also added the CoreMessage function to react to a EVMSG_TIMECHANGED

                    What i'm doing,
                    disable the track (so we can have a feedback of the changes)
                    update the parameter
                    create a key (so we still have the feedback)
                    enable the track(as we have created a key, the object doesn't move)
                    I've also create a "FindCylinder" function so you can create the cylinder after you have launch your GeDialog. And it's easier (but maybe not optimized) to check if the cylinder exist or not.

                    import c4d
                    import sys
                    from c4d import bitmaps, documents, gui, plugins, threading, utils
                    
                    
                    PLUGIN_ID   = 18113999  # Just test ID. Not for production.
                    class MyDialog(c4d.gui.GeDialog):
                        def __init__(self):
                            self.tracklist =  [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE]
                            self.finger_B_01_L_con = None
                    
                        def DesactivateTracks(self, op):
                            ''' Disable a track if it is on the tracklist'''
                            # Retrieves the tracks.
                            tracks = op.GetCTracks()
                            
                            # For each track check if it's on the tracklist                
                            for track in tracks:
                                did = track.GetDescriptionID()
                        
                                # If the Parameter ID of the current CTracks is not on the self.tracklist we go to the next one.
                                if not did[0].id in self.tracklist:
                                    continue
                        
                                track.SetBit(c4d.BIT_ANIM_OFF)
                                
                        def ActivateTracks(self, op):
                            ''' Enable on of the track in the tracklist if founded'''
                            # Retrieves the tracks.
                            tracks = op.GetCTracks()
                    
                            # For each track check if it's on the tracklist        
                            for track in tracks:
                                did = track.GetDescriptionID()
                        
                                # If the Parameter ID of the current CTracks is not on the self.tracklist we go to the next one.
                                if not did[0].id in self.tracklist:
                                    continue
                        
                                track.DelBit(c4d.BIT_ANIM_OFF)
                    
                        def FindCylinder(self, name):
                                ''' function that will help to find an object in the document'''
                                self.doc = c4d.documents.GetActiveDocument()
                                self.finger_B_01_L_con = self.doc.SearchObject(name)
                                return self.finger_B_01_L_con
                    
                        def CreateLayout(self):
                            self.AddEditNumberArrows(id=404040, flags=c4d.BFH_LEFT, initw=100, inith=0)
                            return True
                    
                    
                        def InitValues(self):
                            if self.FindCylinder('Cylinder') is None:
                                return True
                    
                            val = self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z]
                            self.SetDegree(404040, val, min=-180, max=180, step=1, tristate=False)
                            return True
                    
                    
                        def Message(self, msg, result):
                          
                            if msg.GetId() == c4d.BFM_INTERACTEND:      
                                self.InitValues()
                                return True
                    
                            return c4d.gui.GeDialog.Message(self, msg, result)
                    
                        def Command (self, id, msg):
                            if id == 404040:
                                if self.FindCylinder('Cylinder') is None:
                                    print "no object found"
                                    return True
                    
                                ID_AUTOKEYING_COMMAND = 12425
                            
                                previousAutokeyEnableState = c4d.IsCommandChecked(ID_AUTOKEYING_COMMAND)
                                if not previousAutokeyEnableState:
                                    c4d.CallCommand(ID_AUTOKEYING_COMMAND)
                    
                                        
                                self.DesactivateTracks(self.finger_B_01_L_con)
                                self.doc.StartUndo()
                                self.doc.AddUndo(c4d.UNDOTYPE_CHANGE, self.finger_B_01_L_con)
                                undoObj = self.doc.GetUndoPtr()
                                self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = self.GetFloat(404040)
                                #self.ActivateTracks(self.finger_B_01_L_con)
                                
                                self.doc.AutoKey(self.finger_B_01_L_con, undoObj, False, True, True, True, True, True)
                                self.doc.Record()
                    
                                c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW | c4d.DRAWFLAGS_NO_THREAD | c4d.DRAWFLAGS_NO_REDUCTION | c4d.DRAWFLAGS_STATICBREAK)        
                                self.ActivateTracks(self.finger_B_01_L_con)
                    
                                self.doc.EndUndo()
                    
                                if not previousAutokeyEnableState:
                                    c4d.CallCommand(ID_AUTOKEYING_COMMAND)
                                            
                    
                            return True
                    
                        def CoreMessage(self, id, msg):
                            # react to the core message time changed so we can update the UI with the correct value.
                            if id == c4d.EVMSG_TIMECHANGED:
                                self.InitValues()
                    
                            return True
                    
                    class MyMenuPlugin(plugins.CommandData):
                        dialog = None
                        def Execute(self, doc):
                        # create the dialog
                           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)
                        def RestoreLayout(self, sec_ref):
                        # manage the dialog
                           if self.dialog is None:
                              self.dialog = MyDialog()
                           return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)
                    if __name__ == "__main__":
                        okyn = plugins.RegisterCommandPlugin(PLUGIN_ID, "Key Objects Interactively",0, None, "Key Objects Interactively", MyMenuPlugin())
                        if (okyn):
                            print "Key Objects Interactively"
                    

                    cheers,
                    Manuel.

                    MAXON SDK Specialist

                    MAXON Registered Developer

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

                      Hi @m_magalhaes

                      Thanks for the update and sorry for the trouble.
                      I can confirm that it is working as expected.

                      Thank you again.

                      1 Reply Last reply Reply Quote 0
                      • ManuelM
                        Manuel
                        last edited by

                        hi,

                        no trouble at all, you are here to ask questions, we are here to answer.

                        Cheers,
                        Manuel.

                        MAXON SDK Specialist

                        MAXON Registered Developer

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