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).
split from this thread
Hello,
I made some unsuccessful researches about how to access to the selected value of a CUSTOMGUI QUICKTABRADIO declared in a Resource File. I found some examples on how to create and use a QuickTab using GeDialog, but none using .RES.
CUSTOMGUI QUICKTABRADIO
@ferdinand, based on the ID_CA_MUSCLE_OBJECT_STATE you wrote above, how do you access to the LONG ID_CA_MUSCLE_OBJECT_STATE value inside the Execute() or Message()? I didn't fount any way to get the right message update when clicking the options on the Cycle.
ID_CA_MUSCLE_OBJECT_STATE
LONG ID_CA_MUSCLE_OBJECT_STATE
Execute()
Message()
Until now I totally failed to get the selected value from it, I only get 0 when the first element of the cycle is clicked and nothing on the others.
Any clue or example would be more than welcome!
Thanks a lot Christophe
Thanks a lot @m_adam for this detailed answer. I missed that post about the SceneHook method in C++ - as our main plugin is already in C++, maybe we can incorporate this SceneHook inside it instead of having a perpetual running timer checking for a scene change in Python.
Are you aware if there some example somewhere in the SDK talking about this?
Cheer, Christophe
Hi there,
I'm trying to find a way to detect in a Python plugin a document change when I'm switching between different document in C4D. The switch do not concern file open, then close, and open an other document, but really having 2 or 3 different scenes opened at the same time and switching from one to an another.
I went through the different post here, but I didn't found anything relevant, only few tracks, and also some C++ examples but they have some functions that are not existing in Python (ie GeDialog::CheckCoreMessage()). The best example I found is in C++ there : https://developers.maxon.net/docs/Cinema4DCPPSDK/html/page_manual_gedialog.html#page_manual_gedialog_interaction_global_events But the scope of EVMSG_CHANGE is too wide and appears for many operations and not only windows/doc switching.
GeDialog::CheckCoreMessage()
EVMSG_CHANGE
I tried to trace the msg IDs inside CoreMessage(), but I didn't found the correspondance for the IDs that I traced in console.
For example I'm getting this when switching between opened documents:
Python extract for the CoreMessage call,
def CoreMessage(self, id, msg): doc = c4d.documents.GetActiveDocument() # if id == c4d.EVMSG_CHANGE: if msg.GetId() != 1298360653: print ( f"COREMSG_ID {msg.GetId()}" )
In console,
COREMSG_ID 1937337955
I'm skipping the COREMSG_ID = 1298360653 otherwise I'm filing the console in a blink of an eye - it's maybe the redraw or evaluate scene.
COREMSG_ID = 1298360653
I tried to explore the ge_prepass.h file but didn't found any match. Where are located those ID Core Message definitions and their related readable values?
ge_prepass.h
That would helps me to found the right ID message called when switching.
Then, I thought analyse the doc.GetDocumentName() once I do know that I effectively switch from a document to an another.
doc.GetDocumentName()
If someone have some answers, just let me know, it would be really helpful!
Thanks! Christophe
Thanks a lot @cairyn for your answer. Yes, that's a super old thread, but it's the one talking about CollieMouse Do you have a link to get / buy it? The only link I found is about a v1.2 free, which is not working under R23.
Thanks a lot! Christophe
Hello @Cairyn, do you have now a working version of CollieMouse working for R23 and higher? If yes, could we have a short talk about it? Thanks a lot, Christophe
I noticed by having a look on other .res files that there is a STATICTEXT { JOINEND; } that exists and can be applied on LAYERGROUP as well as STATICTEXT { NEWLINE; } but I didn't got the use of the last one as that does not create the "\r" or "\r\n" it should.
STATICTEXT { JOINEND; }
LAYERGROUP
STATICTEXT { NEWLINE; }
Didn't found any informations in the SDK (C++ nor Python) about JOINEND and JOINENDSCALE... those tags looks like to be undocumented.
JOINEND
JOINENDSCALE
I finally end up to format all the elements the way I wand thanks to @ferdinand's link. Indeed STATICTEXT { JOINENDSCALE; } is the trick to proper format your elements when you want to use COLUMNS in GROUP.
STATICTEXT { JOINENDSCALE; }
COLUMNS
GROUP
Here the result in picture,
And the code extract from the .str for whom are interested,
GROUP mGRPAXIS { DEFAULT 1; SEPARATOR { SCALE_H; } GROUP { DEFAULT 1; COLUMNS 4; STATICTEXT mPOSITION { SCALE_H; } STATICTEXT mENPOS { } STATICTEXT mROTATION { SCALE_H; } STATICTEXT mENROT { } STATICTEXT { JOINENDSCALE; } } GROUP { DEFAULT 1; COLUMNS 4; REAL mTX { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; SCALE_H; } BOOL mEN_TX { ANIM OFF;} REAL mRX { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; SCALE_H; } BOOL mEN_RX { ANIM OFF; } STATICTEXT { JOINENDSCALE; } REAL mTY { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; SCALE_H; } BOOL mEN_TY { ANIM OFF; } REAL mRY { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; SCALE_H; } BOOL mEN_RY { ANIM OFF; } STATICTEXT { JOINENDSCALE; } REAL mTZ { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; SCALE_H; } BOOL mEN_TZ { ANIM OFF; } REAL mRZ { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; SCALE_H; } BOOL mEN_RZ { ANIM OFF; } STATICTEXT { JOINENDSCALE; } } SEPARATOR { LINE; SCALE_H; } BUTTON mREMOVE_MOTION { ANIM OFF; } }
Thanks again to the community and plugincafe! Cheers,
Christophe.
Oh! I missed this thread... did thought about searching LAYOUTGROUP, thanks a lot @ferdinand; I going to try this right away and keep you in touch!
Why all those tricks do not appears in SDK? maybe with a bunch of examples it will shorten the learning curve for a lot of people
@orestiskon, self is used because the example is an extract of a class. In my case, those variables are defined in the def __init__ (self):, and belongs to the class object. They are not globals. Have a look there, https://docs.python.org/3/tutorial/classes.html you will understand it with a much better explanation than mine.
def __init__ (self):
If you plan to do not use that inside a class, you can get rid of self of course. Just be careful of doc and op used here below as they are arguments of def Execute(self, tag, doc, op, bt, priority, flags): used in my BaseTag plugin.
self
doc
op
def Execute(self, tag, doc, op, bt, priority, flags):
Knowing this, I assume you can easily transpose this to your purpose as the following example won't work as it is
bcDATAS = c4d.BaseContainer() bcDATAS[ myData ] = "A string for example" # Be sure to use a unique ID obtained at https://plugincafe.maxon.net/c4dpluginid_cp myPLUGIN_ID = 0123456789 # Get the Document Settings BaseContainer bcDoc = doc.GetDocumentData( c4d.DOCUMENTSETTINGS_DOCUMENT ) bcDoc[ myPLUGIN_ID ] = bcDATAS # Store plugin container inside the document container # Save the updated Document BC op.SetData( bcDoc ) # To retrieve a data print ( op.GetData()[ myPLUGIN_ID ][ myData ] )
Hi @orestiskon,
From what I learnt recently, if you have more than one data to store, you can create a sub container of the base container identified by the pluginID.
I can't remember where I read that... just be careful I'm not an advanced C4D developer
In a class for a BaseTag I use this like that,
self.bcDATAS = c4d.BaseContainer() self.bcDATAS[ myData ] = "A string for example" # Be sure to use a unique ID obtained at https://plugincafe.maxon.net/c4dpluginid_cp myPLUGIN_ID = 0123456789 # Get the Document Settings BaseContainer self.bcDoc = doc.GetDocumentData( c4d.DOCUMENTSETTINGS_DOCUMENT ) self.bcDoc[ myPLUGIN_ID ] = self.bcDATAS # Store plugin container inside the document container # Save the updated Document BC op.SetData( self.bcDoc ) # To retrieve a data print ( op.GetData()[ myPLUGIN_ID ][ myData ] )
Cheers,
Christophe
Hi @m_adam,
Good point, here the content for the both files. This .res is for a BaseList2D so SCALEFIT do not apply there.
I hope it will helps... Thanks,
TmotionLab.res
STRINGTABLE TmotionLab { TmotionLab "Plugin"; mPLUGIN_DEF ""; mGRPSCENE "Scene informations"; mGRPAXIS "Axis"; mPROJECT "Project"; mSCENE "Scene "; mTAKE "Take "; mAXIS_EN "Enabling"; mAXIS_MOTION "Motion"; mENPOS "Translation"; mTRANSLATION "XYZ Translation"; mEN_TX "tX"; mEN_TY "tY"; mEN_TZ "tZ"; mROTATION "XYZ Rotation "; mENROT "Rotation "; mEN_RX "rX"; mEN_RY "rY"; mEN_RZ "rZ"; mTX "tX"; mTY "tY"; mTZ "tZ"; mRX "rX"; mRY "rY"; mRZ "rZ"; mREMOVE_MOTION "Remove motion"; }
And the TmotionLab.h,
TmotionLab.h
#pragma once enum { TmotionLab = 1000, mPLUGIN_DEF, mGRPSCENE = 1100, mGRPAXIS, mPROJECT = 1200, mSCENE, mTAKE, mSEP_GRP_A = 1300, mSEP_GRP_B, mTRANSLATION = 1400, mENPOS, mROTATION = 1450, mENROT, mEN_TX = 1500, mEN_TY, mEN_TZ, mEN_RX = 1600, mEN_RY, mEN_RZ, mTX = 2000, mTY, mTZ, mRX = 2200, mRY, mRZ, mREMOVE_MOTION = 5000, };
Dear community,
I getting on fight with my .res file and I still don't get the result I want. I would like to use 2 columns formatting and get the elements spreads on those columns, but for an unknown reason, the space filled by the columns are not as wide as the dialog itself.
I really tried many options on the GROUP mGRPAXIS, with SCALE_H; on REALSLIDER elements or on the subgroups without success. Is that a limitation of the .RES / SDK in Python or is there a trick? In the meantime, all the elements of GROUP mGRPSCENE are properly formatted.
GROUP mGRPAXIS
SCALE_H;
REALSLIDER
GROUP mGRPSCENE
Here the code of the .res file and the result I'm getting as a screenshoot. It's a work in progress dialog, but I would really like to understand if there is a way to get this or not? Can the sliders columns be as wide as the dialog?
CONTAINER TmotionLab { NAME TmotionLab; GROUP { SEPARATOR { } STATICTEXT mPLUGIN_DEF { } SEPARATOR { } GROUP mGRPSCENE { DEFAULT 1; GROUP { STRING mPROJECT { ANIM OFF; SCALE_H; } } GROUP { COLUMNS 2; STRING mSCENE { ANIM OFF; SCALE_H; } LONG mTAKE { MIN 1; MAX 200; STEP 1; ANIM OFF; } } } GROUP mGRPAXIS { DEFAULT 1; SEPARATOR mSEP_GRP_A { NAME mAXIS_EN; LINE; SCALE_H; FIT_H; } GROUP { COLUMNS 2; LAYOUTGROUP; GROUP { STATICTEXT mENPOS { SCALE_H; } BOOL mEN_TX { ANIM OFF; SCALE_H; } BOOL mEN_TY { ANIM OFF; SCALE_H; } BOOL mEN_TZ { ANIM OFF; SCALE_H; } } GROUP { STATICTEXT mENROT { SCALE_H; } BOOL mEN_RX { ANIM OFF; SCALE_H; } BOOL mEN_RY { ANIM OFF; SCALE_H; } BOOL mEN_RZ { ANIM OFF; SCALE_H; } } } SEPARATOR mSEP_GRP_B { NAME mAXIS_MOTION; LINE; SCALE_H; FIT_H; } GROUP { COLUMNS 2; LAYOUTGROUP; GROUP { STATICTEXT mTRANSLATION { SCALE_H; } REAL mTX { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; SCALE_H; } REAL mTY { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; SCALE_H; } REAL mTZ { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; SCALE_H; } } GROUP { STATICTEXT mROTATION { SCALE_H; } REAL mRX { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; } REAL mRY { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; } REAL mRZ { MIN -100.0; MAX 100.0; UNIT PERCENT; CUSTOMGUI REALSLIDER; } } } SEPARATOR { LINE; SCALE_H; } BUTTON mREMOVE_MOTION { ANIM OFF; } } } }
Thanks a lot, Christophe
Hello @ferdinand, thanks a lot for your time and reply. I indeed discovered that the code was for Python 2 when I went I bit further in the code analysis. I thought it was a c4d library, and that's was my mistake and indeed it was totally out of the scope to place it here; sorry. In the meantime, I got rid of that class and made my own iterator method - not a class itself like you did to update the old one (but that's also a good idea).
It was quite easy to iterate all the tags by simply use GetTags() which gives the following,
GetTags()
tags = obj.GetTags() if tags is not None: for tag in tags: print (tag.GetTypeName() + " found") self.tagList.append(tag)
Thanks for your time! Christophe
I went a but further in this old code and discover that the plugin was based on the class I linked in my previous post. There is now better ways to get the same result with BaseObject.GetTags(). I simply got rid of this class and change the code to parse everything. Done.
BaseObject.GetTags()
Cheers.
I changed my code to use BaseDocument.SearchObject(self, name) and it is working perfectly without compromising anything.
BaseDocument.SearchObject(self, name)
Thanks again, Cheers,
Hello folks,
I trying to update a plugin which has been developed for C4D R21.x and Python 2 to C4D R23 and higher which is running Python 3. I got almost everything working now except a redundant issue I'm getting with ObjectIterator() parsing. So, I wondering if the use I made of it is wrong, or if this lib is depreciated?
ObjectIterator()
Here the code running under Python 2 without any issues on C4D R21,
def RetreiveTags(self): self.tagList = [] obj = self.cacheDoc.GetFirstObject() scene = ObjectIterator(obj) for obj in scene: tags = TagIterator(obj) for tag in tags: self.tagList.append(tag)
But while I'm running the same code under C4D R23 with Python 3 I'm getting this error:
Traceback (most recent call last): File "TestIterator.pyp", line 204, in CoreMessage self.RetreiveTags() File "TestIterator.pyp", line 160, in RetreiveTags for obj in scene: TypeError: iter() returned non-iterator of type 'ObjectIterator'
The line in error, is the one with the for tag in tags:
for tag in tags:
After some readings, especially this one http://cgrebel.com/2015/03/c4d-python-scene-iterator/ , I assume that the error comes from the raise StopIteration
raise StopIteration
Is there a way to get this library works normally as it was under R21 or should I update the code like I already did with my own iterator for object list?
Any advises are as usual more than welcome! Thanks a lot,
Thanks for the advices @ferdinand, I think I'm gonna change some parts of my code to avoid this and keep the C4D conventions; I think that I can find a workaround on this.
Cheers, Christophe
My learning curve is improving, but I'm still a newbie here... I wrote my first plugin, but I noticed that when you click on the TAG associated to an object, that does not select the object itself.
Is there a way to have the object selected when the user select its associated Tag plugin?
I had a look on several function like doc.SearchObject() or doc.SetActiveObject() but I'm not sure what the best practices are to do so.
doc.SearchObject()
doc.SetActiveObject()
Does this call must be place into the Message() when a flag is raised or should it be placed into the Execute() (from what I understood, I think that is not the right place)?
If someone have some advices or tips about this it would be more than welcome.
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
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!