Solved 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

MAXON SDK Specialist

MAXON Registered Developer

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!