Finding Control ID in ObjectData Plugin Message() Override
-
Hello,
I have an Integer control that I want to use for presets in my ObjectData plugin. I'm currently storing a variable_preset
in my__init__
override and then checking for a different value when I detect aMSG_DESCRIPTION_USERINTERACTION_END
message in myMessage
override. It works, but it is currently checking this value with every control change since the UserInteraction Messages do not pass IDs (data
is None) and there is no Command method as in a GeDialog. I have a lot of controls, so for efficiency, how can I only check this when the control ID is the Preset Integer in my ObjectData plugin? Thank you!def __init__(self, *args): super(Demo, self).__init__(*args) self._preset = 1
def Message(self, node, type, data): if type == c4d.MSG_DESCRIPTION_USERINTERACTION_END: if self._preset != node[c4d.DEMO_PRESETS]: self._preset = node[c4d.DEMO_PRESETS] self.ApplyPreset()
-
Hi:
Assuming that you are creating a Python plug-in instead of a C++ plug-in, there are two solutions.
The first is to compare the variable data after the control is updated after the plug-in's name stores the previous variable data.If the data is not the same, it is executed to avoid repeated runs.
The second is to create a polygon cache, for example by storing the previous variable data with the local coordinates of the first point, and comparing variable data after the control is updated.If the data is not the same, it is executed to avoid repeated runs.
Python plug-ins actually update automatically, even with every click of the mouse, which often leads to very heavy delays.All dirty systems can be used to detect if an update has occurred.
There should be a better solution to your problem.
Here are examples of Python tags and links to examples : link text
import c4d #e-mail: [email protected] def main(): Name = op.GetName() Objects = op.GetObject() Changed = Objects.GetDirty(c4d.DIRTYFLAGS_SELECT) Text = ["xit" + str(Changed)[-1]] if str(Name).count(Text[0][:-1]) != 0 : if str(Name).find(Text[0][:-1]) != str(Name).rfind(Text[0][:-1]) : if str(Name)[str(Name).rfind(Text[0][:-1]):] == Text[0] : if str(Name).find(Text[0][:-1]) <= 0: #Do not execute, exit the program. print ("Does not perform.") op.SetName(str(Text[0])) return else: #Do not execute, exit the program. op.SetName(str(Name)[:str(Name).find(Text[0][:-1])] + str(Text[0])) print ("Does not perform.") return else: if str(Name).find(Text[0][:-1]) <= 0: op.SetName(str(Text[0])) print ("Perform.") else: op.SetName(str(Name)[:str(Name).find(Text[0][:-1])] + str(Text[0])) print ("Perform.") else: if str(Name)[str(Name).rfind(Text[0][:-1]):] == Text[0] : #Do not execute, exit the program. print ("Does not perform.") return else: op.SetName(str(Name)[:str(Name).find(Text[0][:-1])] + str(Text[0])) print ("Perform.") else: print ("Perform.") op.SetName(str(Name) + str(Text[0])) print ("pass") #The next thing to execute.
-
@x_nerve Thank you for the reply, but I don't think my question was understood. First, I tagged this post with Python, so yes, it is a Python plugin.
Second, as mentioned in the original post, I am already able to compare whether or not the control variable has changed. As mentioned in the topic title, I'm looking to determine the control's ID from NodeData.Message so I don't have to do this check every time a control is edited.
Finally, I'm creating an ObjectData plugin and the Python tag example didn't make sense to me. How is this related to detecting a Control ID from User Interaction?
I do appreciate the effort, thank you. I hope my intentions are clearer now.
-
Hi @blastframe,
thank you for reaching out to us. Regarding your question, one way to do it, is to listen to
MSG_DESCRIPTION_POSTSETPARAMETER
, where the corresponding message data will be theDesscID
of the attribute this message has been raised for. Below you will find both a script and a scene which demonstrate that. I am aware that you are inObjectData
scenario, but I am confident that you get the gist of itCheers,
Ferdinand"""Demonstrates how to react to specific attribute changes in a node for: https://developers.maxon.net/forum/topic/13001 The node has one user data attribute called "Monitored Attribute". Changing that attribute will cause a different print out in the console than any other attribute (user data or not). """ import c4d def main(): return c4d.BaseObject(c4d.Ocube) def message(mid, data): """Reacts to parameter changes of the node. Limits the reaction to specific DescIds by unpacking the message data. Note: Since this was written for scripting object, the signature of the message function differs slightly from NodeData.Message(), but I think you got that ;) Args: mid (int): The message id. data (any): The message data. """ # Listen for parameter changes. if mid == c4d.MSG_DESCRIPTION_POSTSETPARAMETER: # Unpack the message data which contain the DescID of the attribute, # this message has been raised for. descid = data["descid"] # When the message data points to our monitored attribute. This here # is a rather special case, since user data are inherently represented # as multilevel DescIds. For your run of the mill attribute it will # be just descid[0].id == ID_YOU_ARE_INTERESTED_IN. if descid[0].id == c4d.ID_USERDATA and descid[1].id == 1: print ("Monitored Attribute") # All other cases. else: print ("Ignored Attribute")
-
@zipit Thank you, Ferdinand, for the answer and the example scene.
So when one control is changed, it appears that every attribute sends a
c4d.MSG_DESCRIPTION_POSTSETPARAMETER
message, is that correct?If I print the
descid
from your code in my plugin, it prints descids for all of my attributes. I must not have understood this message correctly: I thought it was for one attribute's change. -
Hi @blastframe,
could provide a code snippet for your
NodeData.Mesage()
which produces the output shown above? It would help to simplify the communication a bit.Cheers,
Ferdinand -
@zipit Hi Ferdinand. It's almost the same as yours, just with the other NodeData.Message() parameters and a print statement for the
descid
.def Message(self, node, type, data): if type == c4d.MSG_DESCRIPTION_POSTSETPARAMETER: descid = data["descid"] print(descid)
-
Hi @blastframe,
well, you aren't doing anything with your
DescID
, so of course it will print everythingCinema's message system can be thought of as a more old school version of an event system you might be more familiar with. You have certain events, i.e. message channels, which are used to transport/convey certain information. Some messages are only used to convey that something has happened which broadly falls within the scope of that message. Many messages however, send along some message data which specify the circumstances of that message.
So in your
NodeData.Message()
, there will arrive multiple types of messages with multiple types of message data attached to them. One of them isMSG_DESCRIPTION_POSTSETPARAMETER
, which is raised after a parameter has been changed. Along with it will be sent theDescID
of the parameter which has been modified. When you now want to react to the modification of a specific parameter, you have to evaluate both the message and the message data, like I have shown above in my example. Below you will find a snippet specific to your scenario, unless I am completely misunderstanding you.I hope this helps and cheers,
Ferdinanddef Message(self, node, type, data): """Pretty much the same thing as the previous example, just less abstract. """ if type == c4d.MSG_DESCRIPTION_POSTSETPARAMETER: # Should not happen, but being a bit paranoid can be good thing ;) if (not isinstance(data, dict) or "descid" not in data or not isinstance(data["descid"], c4d.DescID)): msg = "Malformed message data." raise ValueError(msg) descid = data["descid"] # Your DEMO_PRESETS parameter has been modified. if descid[0].id == c4d.DEMO_PRESETS: print ("c4d.DEMO_PRESETS has been modified") # React to other stuff ... return True
-
@zipit Hi, thank you for the message. Yes, I believe I already understood everything you explained and I do appreciate your efforts. I knew I wasn't doing anything with the
descid
in my code, I was just confused as to why when I change one attribute, I was gettingMSG_DESCRIPTION_POSTSETPARAMETER
messages from all of the attributes as opposed to just the one attribute. Perhaps it is something else in my code that is sending those. Regardless, it isn't hugely important, I was trying to be as efficient as possible.Thank you.