Detecting Rename
-
Hello,
Is it possible to get information about the event when an object has been renamed? I'm currently listening for theEVMSG_CHANGE
Core Message but I getNone
when I printBFM_CORE_PAR1
andBFM_CORE_PAR2.
I tried looking for other messages, butEVMSG_CHANGE
seemed like the right one. I would like to find out what the object's name was before and after the change.def CoreMessage(self, id, msg): if id == c4d.EVMSG_CHANGE: for id, data in msg: if str(type(data))=="<type 'PyCObject'>": pythonapi.PyCObject_AsVoidPtr.restype = c_void_p pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object] data = pythonapi.PyCObject_AsVoidPtr(data) print id, data return True
Thank you!
-
Hi,
I am not the biggest expert on Cinema's core message system, but AFAIK
EVMSG_CHANGE
is only being broadcasted for modification of the scene graph or similar events, not the modification of nodes.Messages for the modification of nodes are being sent as atom messages (
C4DAtom.Message
) and there is unfortunately currently no way in Cinema to subscribe to such events from the outside. Cinema's closest thing to that would beC4DAtom.GetDirty
, which will, among other things, allow you to track the dirty state of the data container (a.k.a. the attributes) of the node, but would have to be checked regularly by yourself.But this all seems overly complicated for such a simple task, simply design an object that regularly checks the names of the nodes that it is meant to monitor. One solution could be a
MessageData
plugin with its timer method.Also: I am also not quite sure what you are trying to do there with the
PyCObject
in your code. It just holds a void pointer, i.e. an address and a block size for a memory region. The type is mostly useless in Python itself and only comes in handy when you use Python as a glue-language between two C(++) applications (i.e. is heavily used by Python itself internally). You can technically parse some basic C-types with Python'sstruct
if you know their memory location, but that won't work with anything more complicated.Cheers,
zipit -
Hi @blastframe
To be more precise EVMSG_CHANGE is called when an EventAdd is processed, which is normally done after a SetName but not mandatory.
SetName actually set the dirty
c4d.DIRTYFLAGS_DATA
on the renamed element. Moreover, the MSG_NOTIFY_EVENT is also sent so that means any BaseList2D can receive a notification when the other object is renamed.
Here a short example with a Tag listening for the renaming of its host object.import c4d def message(msgType, data): if msgType == c4d.MSG_NOTIFY_EVENT: if data["eventid"] == c4d.NOTIFY_EVENT_SETNAME: renamedObj = data["bl"] print(renamedObj.GetName()) def main(): obj = op.GetObject() if not obj.FindEventNotification(doc, op, c4d.NOTIFY_EVENT_SETNAME): obj.AddEventNotification(op, c4d.NOTIFY_EVENT_SETNAME, 0, c4d.BaseContainer()) if __name__=='__main__': main()
Note that AddEventNotification is to be used with extreme care as you can screw up the Cinema 4D message system. so please only read the data and don't do infinite change (aka renaming the initial object, since it will trigger another MSG_NOTIFY_EVENT message and you can easily end with an infinite loop).
Finally, another way to achieve what you want is to have a list of tuples of object and associate name.
Then within a Timer check if the name changed by iterating this list.Cheers,
Maxime -
@zipit and @m_adam , thank you for the replies.
@zipit , I have no clue what the
PyCObject
code is doing: I found that code in a few threads on this forum for decipheringBFM_CORE_PAR1
andBFM_CORE_PAR2
from the CoreMessage. It doesn't seem to find any information.@m_adam , is there a way to listen to
NOTIFY_EVENT_SETNAME
from a GeDialog? Sorry, I forgot to mention that I'd be doing this from a Command Plugin and a GeDialog.Thank you!
-
Can I ask if it is possible to get a notification when
- the generator bit gets changed?
- the visibility / render bits get changed?
there doesnt seem to be a NOTIFY_EVENT for these actions...
-
For the generator bit, this can be somehow done via
import c4d def message(msgType, data): if msgType == c4d.MSG_NOTIFY_EVENT: if data["event_data"]["msg_id"] == c4d.MSG_DEFORMMODECHANGED: print(data) def main(): obj = doc.GetFirstObject() if not obj.FindEventNotification(doc, op, c4d.NOTIFY_EVENT_MESSAGE): obj.AddEventNotification(op, c4d.NOTIFY_EVENT_MESSAGE , 0, c4d.BaseContainer()) if __name__=='__main__': main()
The main issue is it's triggered only after an EventAdd so this means most of the time you will not get the change immediately.
Regarding the visibility, this is unfortunately not possible, since SetEditorMode/SetRenderMode only do a SetDirty(DIRTYFLAGS::MATRIX) internally. And the dirty state is not monitored by the Event Notification system.
One side note it's possible to use
MSG_DESCRIPTION_POSTSETPARAMETER
like in the snippet bellow, but this message is sent by the Attribute Manager when a parameter is set, so that means if you change the value within the Attribute Manager of the Editor display mode, the change will be monitored, but if you change the mode via the Object Manager, which directly use SetEditorMode, then the message is not sent.import c4d def message(msgType, data): if msgType == c4d.MSG_NOTIFY_EVENT: if data["event_data"]["msg_id"] == c4d.MSG_DESCRIPTION_POSTSETPARAMETER: if data["event_data"]["msg_data"]["descid"] == c4d.DescID(c4d.ID_BASEOBJECT_VISIBILITY_EDITOR): print("changed editor") elif data["event_data"]["msg_data"]["descid"] == c4d.DescID(c4d.ID_BASEOBJECT_VISIBILITY_RENDER): print("changed render") elif data["event_data"]["msg_data"]["descid"] == c4d.DescID(c4d.ID_BASEOBJECT_GENERATOR_FLAG): print("changed generator") def main(): obj = doc.GetFirstObject() if not obj.FindEventNotification(doc, op, c4d.NOTIFY_EVENT_MESSAGE): obj.AddEventNotification(op, c4d.NOTIFY_EVENT_MESSAGE , 0, c4d.BaseContainer()) if __name__=='__main__': main()
Cheers,
Maxime. -
@m_adam Hi Maxime, any notes on the GeDialog question prior to the generator question: Is it possible to listen to a rename event from a GeDialog in a Command Plugin?
-
@m_adam :
thanks, i need it to work when editing live in the object manager. i found a little hack for the generator flag snippet:
like this, i immediately get a msg if i change the generator flag in the object manager. without the print statement it does not work.
do you understand this? i guess its not recommended? .-)just put that script in a python tag on an object with a generator switch (instance for example)
import c4d def message(msgType, data): if msgType == c4d.MSG_NOTIFY_EVENT: if data["event_data"]["msg_id"] == c4d.MSG_DEFORMMODECHANGED: obj = op.GetObject() print(obj.GetName(), obj[c4d.ID_BASEOBJECT_GENERATOR_FLAG]) def main(): obj = op.GetObject() if not obj.FindEventNotification(doc, op, c4d.NOTIFY_EVENT_MESSAGE): obj.AddEventNotification(op, c4d.NOTIFY_EVENT_MESSAGE , 0, c4d.BaseContainer()) print(""), # DIRTY HACK :) if __name__=='__main__': main()
-
@blastframe sorry no there is nothing for a GeDialog, if you are in a GeDialog, your best bet is within the GeDialog's CoreMessage, listen for EVMSG_CHANGE and figured out if the generator changed or not.
@indexofrefraction print will require a redraw as soon as possible, and most important this will consume all messages.
So is it nice? Not really but I guess you don't have other choices.Cheers,
Maxime. -
This post is deleted! -
Hello @blastframe,
without any further questions or replies, we will consider this topic to be solved by Monday and flag it accordingly.
Thank you for your understanding,
Ferdinand