how to track if the document has changed?
-
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 -
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 timerimport 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. -
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? -
Hi correct, if you look at my code I do
oldDoc = self.activeDoc
This means
oldDoc
will call theactiveDoc
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.