Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode.
Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).
Hi there,
I'm working on a simple Tag plugin in Python, which must run under R21.
On the plugin itself, I'm checking inside Execute() if there is a change on the FILENAME field of my GUI. If there is a change, I'm checking the file extension and depending on this I'm proceeding to a conversion upon the agreement of the user to a question.
Execute()
But... if seems that the simple call to c4d.gui.QuestionDialog() makes c4d crash instantly.
c4d.gui.QuestionDialog()
That's the facts.
Honestly, I'm using an identical call to this function elsewhere in the code in Message() without any issue.
Message()
Can this crash occurs because I'm using this in Execute() or can this be related to something I'm doing in a wrong way? Of course I've check the documentation but I didn't notice anything relevant.
Here the excerpt of the code that makes c4d crash.
import sys import os import c4d import time import json from c4d import gui, plugins, bitmaps #../.. Inside the class which define the Tag plug-in def __init__ (self): pass def Init(self, node): return True def Execute(self, tag, doc, op, bt, priority, flags): # .../... currentFILE = self.currentTagData.GetFilename(c4d.mMOTIONFILE_PATH) if self.currentTagData.GetFilename(c4d.mMOTIONFILE_PATH) != self.previousFILE: self.previousFILE = currentFILE if currentFILE.lower().endswith(".json"): # Is a JSON? return True elif currentFILE.lower().endswith(".csv"): # Is a CSV? # CRASH HERE - Ask to convert the CSV file into a JSON one askConvertToJSON = c4d.gui.QuestionDialog("Would you like to convert this file to a compatible JSON?") if not askConvertToJSON: return False return True else: raise ValueError("This file extensoin is not supported, please load a compatible JSON or CSV file") return False return True
Any helps are more than welcome. Thanks!
Hello @mocoloco,
yes, finding the correct message to look for can be a bit tricky. In this case you should listen for MSG_DESCRIPTION_POSTSETPARAMETER, i.e., the message for when some parameter of a node has changed its value. You will find an example as a Python programming tag at the end of the posting which will translate quite directly to NodeData.Message(). It is only that the signature of the message function in a programming tag is slightly different.
NodeData.Message()
message
Cheers, Ferdinand
The scene file: example.c4d
The code:
"""Example for reacting to parameter changes in a NodeData node. """ import c4d def message(mid, mdata): """The equivalent to NodeData.Message(). The signature of NodeData.Message() is a bit different, as it has slightly different arguments and requires you to return something else than None. Args: mid (int): The message type mdata (any): The message data. """ if mid == c4d.MSG_DESCRIPTION_POSTSETPARAMETER: # Here we are in a scripting object with a user data parameter, so # the parameter id is a bit more complex. We are checking if the # raising element was the element with the id (c4d.ID_USERDATA, 1), # i.e., the first user data element. In your case you would have to # only check the first DescLevel in the DescID passed as the message # data for MSG_DESCRIPTION_POSTSETPARAMETER. descId = mdata["descid"] if descId[0].id == c4d.ID_USERDATA and descId[1].id == 1: # When we are in the main-thread, open a dialog. if c4d.threading.GeIsMainThread(): # Op is predefined in a scripting object. In case of a # programming tag it is the tag itself. We simply query the # tag for the value with the DescId which has been sent has # the message data. file = op[descId] c4d.gui.MessageDialog("The the file is: {}".format(file)) def main(): pass
welcome to the forum and the Cinema 4D community and thank you for reaching out to us.
The reason why your plugin is not working, is that your program design is a violation of Cinema 4D's threading restrictions. TagData.Execute is not being called from the main thread, i.e., is being called in parallel. Which makes GUI operations, e.g., opening a dialog, off limits there. For more information on things that are forbidden to do outside of the main thread, please read the mentioned article about threading restrictions. Since your code also does indicate that you are planning to do file operations in TagData.Execute: This will also cause problems when multiple threads try to operate on the same file.
TagData.Execute
You have move such operations to a method of NodeData which you know is being called (at least sometimes) on the main thread. A common candidate is NodeData.Message and listening for a button click. There you can then check for being on the main thread with c4d.threading.GeIsMainThread() and then do anything that would be unsafe to do in asynchronous execution, like modifying the scene graph or doing GUI operations.
NodeData
NodeData.Message
c4d.threading.GeIsMainThread()
Thanks @ferdinana for your message and informations. As it is my first plugin I didn't dig that much in SDK and didn't noticed that..
My first try was to get that information on def Message(), but FILENAME declared on .res when clicked, doesn't fired any message while all other buttons are. This one is not maybe due to the fact that's not really a button, I'm gonna check if an another TYPE is changed with this particular FILENAME.
def Message()
FILENAME declared on .res
TYPE
FILENAME
I will read all this and see if I can figured out with this.
Thanks a lot, Christophe
After some test, I didn't find what message in NodeData check to see if there is any file change on the FILENAME GUI Item ID XXXX. That's frustrating.
I checked the following, that sounds relevant, but they unfortunetly aren't
def Message(self, node, type, data): if type == c4d.MSG_DESCRIPTION_CHECKUPDATE: if type == c4d.MSG_DESCRIPTION_VALIDATE: if type == c4d.MSG_DESCRIPTION_EDIT_ENTRY:
Scanning datas and types didn't helped neither.
I'm just looking for a way to get a acknowledgment from the user prior doing an operation on the file selected... I thought that it could be simpler. If anybody ave a workaround for this and will to share it, please let me know!
Wow, I couldn't have though that I have to watch c4d.MSG_DESCRIPTION_POSTSETPARAMETER. I'm starting to understand the way to use threading as well, thanks a lot for the help and tips, all is working perfectly now.
c4d.MSG_DESCRIPTION_POSTSETPARAMETER