Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware 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

    how to track if the document has changed?

    Cinema 4D SDK
    python
    2
    4
    770
    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.
    • D
      datamilch
      last edited by

      hi there,

      i have a command plugin that is dependent on the state of the active document. so i want to track if the document has changed.

      there seems to be no dedicated core message. so i tried the following. but it gives me "basedocument is not alive", which makes senes in a way. but how can i make it work?

      class MyDialog( ... 
         doc_old = None
         ...
      
         def CoreMessage(self, cid, msg):
              doc = c4d.documents.GetActiveDocument()
              if cid == c4d.EVMSG_CHANGE:
                  if doc != self.doc_old:
                      print ("doc changed")
                      self.doc_old = doc
      

      thanks,
      sebastian

      1 Reply Last reply Reply Quote 1
      • M
        m_adam
        last edited by

        Hi @datamilch when you see the error message "XXX is not alive" this means the actual C++ object that represent your python object does not exist anymore. E.g. in a case of a document the python object just hold a pointer (a memory address pointing to the BaseDocument), so if you close the document, the memory address will not point anymore on a BaseDocument, so to avoid any crash this error is raised.

        The best way to do what you want to achieve is to use a timer, as EVMSG_CHANGE is normally sent to notify that something changed in a scene, so the scene need to be re-evaluated but there is no way to be sure when switching to a new document, this one will be executed (as it may already be). So Find bellow an example dialog using timer

        import c4d
        
        
        class MyDialog(c4d.gui.GeDialog):
        
            def __init__(self):
                self.activeDoc = c4d.documents.GetActiveDocument()
        
            def CreateLayout(self):
                self.SetTimer(500)
                return True
        
            @property
            def activeDoc(self):
                doc = getattr(self, '_activeDoc', None)
                if doc is None:
                    return None
        
                if not doc.IsAlive():
                    return None
        
                return doc
        
            @activeDoc.setter
            def activeDoc(self, value):
                if not isinstance(value, c4d.documents.BaseDocument):
                    raise TypeError("value is not a c4d.documents.BaseDocument.")
        
                self._activeDoc = value
        
            def Timer(self, msg):
                activeDoc = c4d.documents.GetActiveDocument()
                if activeDoc is None:
                    return
        
                if activeDoc != self.activeDoc:
                    oldDoc = self.activeDoc
                    self.activeDoc = activeDoc
                    print("doc changed")
        
        
        def main():
            global diag
        
            diag = MyDialog()
            diag.Open(dlgtype=c4d.DLG_TYPE_ASYNC, defaultw=960, defaulth=600)
        
        
        # Execute main()
        if __name__ == '__main__':
            main()
        

        Cheers,
        Maxime.

        MAXON SDK Specialist

        Development Blog, MAXON Registered Developer

        1 Reply Last reply Reply Quote 0
        • D
          datamilch
          last edited by

          hi maxime,

          thankt you! that works 🙂

          one question:
          you left the 'oldDoc' in there. I suppose because you didn't know if i use it anywhere else - i dont.
          But isn't there the chance, that the value/pointer stored in oldDoc might become not alive at some point? so if i would want to call oldDoc again i'd have to check isAlive() beforehand?

          1 Reply Last reply Reply Quote 0
          • M
            m_adam
            last edited by

            Hi correct, if you look at my code I do

            oldDoc = self.activeDoc
            

            This means oldDoc will call the activeDoc property getter. And within it I already check for IsAlive and return None if the saved document is not alive.

                @property
                def activeDoc(self):
                    doc = getattr(self, '_activeDoc', None)
                    if doc is None:
                        return None
            
                    if not doc.IsAlive():
                        return None
            
                    return doc
            

            So for my use case it's fine enough, but you are right, if you store somewhere this oldDoc variable and use it latter then yes you need to check for IsAlive.

            Cheers,
            Maxime.

            MAXON SDK Specialist

            Development Blog, MAXON Registered Developer

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