Dynamic Update on Plug-ins



  • NOTE: Not talking about updating to new version but updating the execution of the plug-in.

    I have a test plug-in that prints out "There are no objects in the scene" or "There are # objects in the scene".
    It works as expected upon initial open of the plug-in but not through-out.

    You can see an illustration of the problem here:
    https://www.dropbox.com/s/6j0aqtvgg6o2vg6/c4d131_automatic_update-plug-in.mp4?dl=0

    Thank you for looking at my problem

    P.S. I need the LayoutFLushGroup and LayoutChanged in the code since I'm planning to list all objects and all their parameters.

    You can see the illustration code here:

    import c4d
    import os
    from c4d import gui, plugins, bitmaps, utils, documents
    
    
    
    PLUGIN_ID   = 1011321
    
    class MyDialog(gui.GeDialog):
    
    
        def get_all_objects(self, op):
        
          output = []
          
          while op:
              output.append(op)
              self.get_all_objects(op.GetDown())
              op = op.GetNext()
    
          return output
    
        def CreateLayout(self):
    
          doc = c4d.documents.GetActiveDocument()
    
          self.object_count = len(self.get_all_objects(doc.GetFirstObject()))
    
          self.GroupBegin(id=1000, flags=c4d.BFH_FIT, cols=0, rows=4, title="Rigging")
    
    
          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, c4d.BFH_CENTER, name="There are %s objects in the scene" %self.object_count)
            self.LayoutChanged(1001)
    
          self.GroupEnd()
    
          return True
    
        def Command(self, id, msg):
    
            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, "BT Utilities",0, None, "Python Menu", MyMenuPlugin())   
    
    


  • I haven't looked at your dropbox video, but from your explanation I seem to understand you will have to listen and react to message EVMSG_CHANGE. There is no other way to react to objects being added, or removed from the Object Manager.
    Obviously, the EVMSG_CHANGE will be called for every little change that occur in a scene, so you will probably need to filter out "false positives", if you don't want/need to update too frequently.



  • @C4DS
    Thanks for the response. I incorporated the EVMSG_CHANGE. It does not error out but it also does not work as expected (Behavior is still the same as before). Is there a way around this?

    You can check the revised code here:

    import c4d
    import os
    from c4d import gui, plugins, bitmaps, utils, documents
    
    
    
    PLUGIN_ID   = 1011321
    
    class MyDialog(gui.GeDialog):
    
    
        def get_all_objects(self, op):
        
          output = []
          
          while op:
              output.append(op)
              self.get_all_objects(op.GetDown())
              op = op.GetNext()
    
          return output
    
    
        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, c4d.BFH_CENTER, name="There are %s objects in the scene" %self.object_count)
            self.LayoutChanged(1001)
    
        def CreateLayout(self):
    
          doc = c4d.documents.GetActiveDocument()
    
          self.object_count = len(self.get_all_objects(doc.GetFirstObject()))
    
          self.GroupBegin(id=1001, flags=c4d.BFH_FIT, cols=0, rows=4, title="Rigging")
    
          self.GroupEnd()
    
          self.Update() # NEW CODE
    
          return True
    
        def Command(self, id, msg):
    
          return True
    
        def CoreMessage(self, id, msg):
    
          if id == c4d.EVMSG_CHANGE: # NEW CODE
            self.Update()
    
          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, "BT Utilities",0, None, "Python Menu", MyMenuPlugin())   
    


  • hello @bentraje,

    In your code get_all_objects was not called and not updating object_count

    I've changed your code a bit. I've used a non-recursive hierarchy iteration found in our blog so you don't hit the stack limit in case of a big hierarchy.

    InitValues is called after CreateLayout so that's why I've used __init__ in the first place to init my values.

    In my code i'm using self.objectsList to store the object list. It's just for this example, GeDialog is not the best place to store data.

    import c4d
    import os
    from c4d import gui, plugins, bitmaps, utils, documents
    
    
    
    PLUGIN_ID   = 1011321
    
    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
            # https://developers.maxon.net/?p=596
            # 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, c4d.BFH_CENTER, name="There are %s objects in the scene" %self.object_count)
                self.LayoutChanged(1001)
    
        def CreateLayout(self):
    
                    
            print "nombre d'objet ", self.object_count
            self.GroupBegin(id=1001, flags=c4d.BFH_FIT, cols=0, rows=4, title="Rigging")
    
            self.GroupEnd()
    
            self.Update() # NEW CODE
    
            return True
    
        def Command(self, id, msg):
    
            return True
    
    
        def CoreMessage(self, id, msg):
    
            if id == c4d.EVMSG_CHANGE: # NEW CODE
    
                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, "BT Utilities",0, None, "Python Menu", MyMenuPlugin())   
    
    

    Cheers
    Manuel



  • Hi @m_magalhaes

    Thanks for the response and clarification specially with the
    def __init___ and def InitValuesthat was news to me.

    The plug-in works as expected. Have a great day ahead!


Log in to reply