Hello @dglopez,
thank you for clarifying your question. There are unfortunately some things still unclear to me, so let me start with a set of assumptions of mine:
- The other plugin uses a
GeDialog
and is most likely some CommandData
plugin.
- There is a known set of
C4DAtom
, or more specifically BaseObject
, you want to track.
- There is not necessarily a second plugin in your case.
So, there are basically two major ways you can do this. You can either A. push the information into the other plugin from the action of the objects being moved. This option does necessarily need a second plugin which is pushing the information into your other plugin. Or you can B. grab the information from the objects when they have been moved from within the other plugin. This option does not need necessarily a second plugin. Which might sound like semantics is an important distinction, since you cannot move data without restrictions in the message system of Cinema 4D.
When the the other plugin is some GeDialog
, option B lends itself best via core messages and EVMSG_CHANGE
, see end of posting for an example. However, when the other plugin is some kind of classic API node, e.g., an object itself, you will have to push the information into that node, e.g., with MSG_BASECONTAINER
. But depending on how you structure all that, you might need a third plugin in between to handle the transfer. Your question is here unfortunately so broad that I cannot give you anything more concrete.
I hope this helps and cheers,
Ferdinand
The result:

The code:
"""Example for tracking object matrices in a GeDialog.
This can be run as a script manager script and will create a dialog which
tracks the global transform matrices of the objects that have been selected
when the dialog was created.
As discussed in:
https://plugincafe.maxon.net/topic/13643/
"""
import c4d
class ObjectTrackerDialog (c4d.gui.GeDialog):
"""Example dialog that tracks the transforms of a set of objects.
"""
ID_GADGETS_START = 1000
ID_GADGET_GROUP = 0
ID_GADGET_LABEL = 1
ID_GADGET_TEXT = 2
GADGETS_STRIDE = 10
def __init__(self, objects: list[c4d.BaseObject]) -> None:
"""
"""
self._objects = objects
def CoreMessage(self, mid: int, msg: c4d.BaseContainer) -> bool:
"""Receives core messages.
We react here to EVMSG_CHANGE to update all our object matrices.
EVMSG_CHANGE is the message for EventAdd(), i.e., is being fired
ALOT. To make this less throttling, we could also use
GeDialog.SetTimer and GeDialog.Timer to update the matrices in a
fixed interval. What is better depends on how time-consuming you
would consider your updates to be. But the timer approach will also
consume process time when nothing changed. So, the best approach
would be to mix the two. I.e., only react to EVMSG_CHANGE when a
certain time span X has passed since the last time you did react to
it.
"""
if mid == c4d.EVMSG_CHANGE:
self.UpdateValues()
return True
def CreateLayout(self) -> bool:
"""Creates a static text and a text box for each tacked object.
"""
self.SetTitle("ObjectTrackerDialog")
for i, item in enumerate(self._objects):
gid = self.ID_GADGETS_START + i * self.GADGETS_STRIDE
name = item.GetName()
self.GroupBegin(gid + self.ID_GADGET_GROUP,
c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, cols=2)
self.AddStaticText(gid + self.ID_GADGET_LABEL,
c4d.BFH_LEFT | c4d.BFV_SCALEFIT, name=name)
self.AddEditText(gid + self.ID_GADGET_TEXT,
c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT)
self.GroupEnd()
return True
def InitValues(self) -> bool:
"""Initializes the dialog values.
"""
return self.UpdateValues()
def UpdateValues(self) -> bool:
"""Updates the dialog values.
"""
for i, item in enumerate(self._objects):
gid = gid = self.ID_GADGETS_START + i * self.GADGETS_STRIDE
self.SetString(gid + self.ID_GADGET_TEXT, item.GetMg())
return True
def main():
"""Creates an instance of the ObjectTrackerDialog.
"""
items = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_NONE)
if not isinstance(items, list) or len(items) < 1:
raise RuntimeError("Please select at least one object.")
# Please do not do this in a production environment. This is just a hack
# to keep an async dialog alive from the script manager. Which will lead
# to problems when used in production.
global dialog
dialog = ObjectTrackerDialog(items)
dialog.Open(c4d.DLG_TYPE_ASYNC)
if __name__ == '__main__':
main()