Thank you very much @ferdinand, that's exactly what I was looking for.
Cheers
Best posts made by danielsian
Latest posts made by danielsian
Hi there, is it possible to test "Lock Overrides" and return if it is on or off using Python?
The same question for the "Enable all overrides" button.
Cheers
@m_magalhaes said in Copying Take Overrides from an object to another via Python not working properly:
adding the backupvalue
You are master!
thanks my friend, it's working!
Hi there, I'm working on a script to transfer (or copy) the overrides from a source object to a target one and it seems to be working if there is no overrides in sub-Takes.
Basically what the script does is a scan through all Takes starting from the first after the Main (takeData.GetMainTake().GetDown()
) and retrieves each override ID and value and it adds to the target object via FindOrAddOverrideParam()
.
But for any odd reason the result is not consistent if there are sub-Takes involved as it changes depending on which one is active before running the script, and in all cases, I would expect a perfect copy but that's not what's happening. I must be missing something here
My gut feeling says that the problem is related to the backup so I just tried forcing it via FindOverrideCounterPart()
but without success.
I'm sending a dummy file attached with a set of Takes just to show the problem I'm trying to describe here:
copy_overrides_to_another_object.c4d
This is the script that works with the file above:
import c4d
def GetNextTake(op):
if op == None: return None
if op.GetDown(): return op.GetDown()
while not op.GetNext() and op.GetUp(): op = op.GetUp()
return op.GetNext()
def getDescIdName(op, descID):
description = op.GetDescription(c4d.DESCFLAGS_DESC_0)
for bc, paramid, groupid in description:
if paramid == descID:
return bc[c4d.DESC_NAME]
def TransferTakeOverrides(srcObj, trgObj, takeData, currentTake):
while currentTake:
srcOverride = currentTake.FindOverride(takeData, srcObj)
if srcOverride is not None:
for descID in srcOverride.GetAllOverrideDescID():
# Get the backup node for the source override
backup, result = takeData.FindOverrideCounterPart(srcOverride, descID) # backup: The counterpart node // result: the Take
if backup is None:
raise RuntimeError("Failed to find the default override.")
# Get the backup value of the given Description ID
backupValue = backup.GetParameter(descID, c4d.DESCFLAGS_GET_0)
print(currentTake.GetName(), " DescID:", getDescIdName(srcObj,descID))
print(" --->",srcOverride.GetSceneNode().GetName())
print(" overr. value:", srcOverride.GetParameter(descID, c4d.DESCFLAGS_GET_0))
print(" backup value:", backupValue,"from", result.GetName())
# Get the override value
srcOverValue = srcOverride.GetParameter(descID, c4d.DESCFLAGS_GET_0)
# add override to the target object
trgOverride = currentTake.FindOrAddOverrideParam(takeData, trgObj, descID, srcOverValue)
# Get the backup node for the target override
trg_backup, trg_result = takeData.FindOverrideCounterPart(trgOverride, descID)
trg_backupValue = trg_backup.GetParameter(descID, c4d.DESCFLAGS_GET_0)
# force adding source backup value to the target backup take (just trying to fix the problem!)
trgBackup = trg_result.FindOrAddOverrideParam(takeData, trgObj, descID, backupValue)
trgBackup.UpdateSceneNode(takeData, descID)
trgOverride.UpdateSceneNode(takeData, descID)
print(" --->",trgOverride.GetSceneNode().GetName())
print(" overr. value:", trgOverride.GetParameter(descID, c4d.DESCFLAGS_GET_0))
print(" backup value:", trg_backupValue,"from", trg_result.GetName())
print(" ----------------")
currentTake = GetNextTake(currentTake)
print("======================================")
def main():
op = c4d.BaseObject(c4d.Ocube)
op[c4d.ID_BASELIST_NAME] = "trg_Cube"
doc.InsertObject(op)
objs = doc.GetObjects()
objs.reverse()
if len(objs) != 2: return
takeData = doc.GetTakeData()
currentTake = takeData.GetMainTake().GetDown()
TransferTakeOverrides(srcObj=objs[0], trgObj=objs[1], takeData=takeData, currentTake=currentTake)
c4d.EventAdd()
if __name__=='__main__':
main()
@ferdinand Thank you for your awesome explanation!
I will keep this post as a reference for my studies as your approach seems a bit complicated for my understanding at the moment.
I'm learning a lot with your contribution in this forum, and in this case here it's not gonna be different.
Cheers
@cairyn thanks for your time and helpful answer.
I was trying to retrieve the value of a variable from another class by calling it directly. This is why you could see OptionsDialog() within class processing. This is the source of my problems, because as far as I know, this is how a class variable should be called from another class.
Probably I'm wrong or things are different when there's a dialog involved
Anyways, this is the working code, with your solution addressed:
import c4d
pluginVersion = "v1.0.0"
pluginName = "Get Value From Dialog"
PLUGIN_ID = 1111222
class OptionsDialog (c4d.gui.GeDialog):
GROUP_OPTIONS = 1011
CHKBX1 = 1007
CHKBX2 = 1008
CHKBX3 = 1009
BTN_OK = 1010
def __init__(self):
self._hasBeenInitalized = False
self._hasLayoutDone = False
def Message(self, msg, result):
if msg.GetId() == c4d.BFM_ACTION: msg[c4d.BFM_ACTION_VALUE]
return c4d.gui.GeDialog.Message(self, msg, result)
def CreateLayout(self):
self.SetTitle(pluginName + ' ' + pluginVersion)
self.AddCheckbox(self.CHKBX1, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 1')
self.AddCheckbox(self.CHKBX2, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 2')
self.AddCheckbox(self.CHKBX3, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 3')
if self.GroupBegin(self.GROUP_OPTIONS, c4d.BFH_CENTER, 1, 1):
self.AddButton(self.BTN_OK, c4d.BFH_SCALEFIT, initw=500, inith=15,name='Go!')
self.GroupEnd()
self._hasLayoutDone = True
self._hasBeenInitalized = False
return True
def Command(self, id, msg):
if id==self.BTN_OK or id==c4d.IDC_OK:
self.print_msg1 = self.GetBool(self.CHKBX1)
self.print_msg2 = self.GetBool(self.CHKBX2)
self.print_msg3 = self.GetBool(self.CHKBX3)
self.Run()
return True
def InitValues(self):
if self._hasBeenInitalized is True:
return True
self.SetBool(self.CHKBX1, True)
self._hasBeenInitalized = True
return True
def Run(self):
message = processing().set_nice_message(self.print_msg1, self.print_msg2, self.print_msg3)
print(message)
c4d.EventAdd()
return True
class processing:
def set_nice_message(self, msg1, msg2, msg3):
if msg1: result = 'Hello world 1'
if msg2: result = 'Hello world 2'
if msg3: result = 'Hello world 3'
return result
class DialogCommandData(c4d.plugins.CommandData):
dlg = None
def Execute(self, doc):
if self.dlg is None:
self.dlg = OptionsDialog()
return self.dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC,
pluginid=PLUGIN_ID,
xpos=-2, ypos=-2, defaultw=720, defaulth=50)
def RestoreLayout(self, secret):
if self.dlg is None:
self.dlg = OptionsDialog()
return self.dlg.Restore(pluginid=PLUGIN_ID, secret=secret)
if __name__ == '__main__':
myPlugin = DialogCommandData()
c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID,
str=pluginName,
info=0,
icon=None,
help=pluginName,
dat=myPlugin)
This is probably a silly question, but I'm stuck and need some help so I can move forward in my plugin without using global dialog.
The original dialog has much more checkboxes and edit texts to guide the whole processing, but I've been able to get a very simplified sample of my code with a similar structure.
I have a class
class processing
that needs to retrieve data from the dialog in order to process the script, but I really don't know how to get it since the code below is returning this error:
AttributeError: 'OptionsDialog' object has no attribute 'print_msg1'
I have to keep the structure like it is at the moment.
This the sample, any help would be awesome:
import c4d
pluginVersion = "v1.0.0"
pluginName = "Get Value From Dialog"
PLUGIN_ID = 1111222
class OptionsDialog (c4d.gui.GeDialog):
GROUP_OPTIONS = 1011
CHKBX1 = 1007
CHKBX2 = 1008
CHKBX3 = 1009
BTN_OK = 1010
def __init__(self):
self._hasBeenInitalized = False
self._hasLayoutDone = False
def Message(self, msg, result):
if msg.GetId() == c4d.BFM_ACTION: msg[c4d.BFM_ACTION_VALUE]
return c4d.gui.GeDialog.Message(self, msg, result)
def CreateLayout(self):
self.SetTitle(pluginName + ' ' + pluginVersion)
self.AddCheckbox(self.CHKBX1, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 1')
self.AddCheckbox(self.CHKBX2, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 2')
self.AddCheckbox(self.CHKBX3, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 3')
if self.GroupBegin(self.GROUP_OPTIONS, c4d.BFH_CENTER, 1, 1):
self.AddButton(self.BTN_OK, c4d.BFH_SCALEFIT, initw=500, inith=15,name='Go!')
self.GroupEnd()
self._hasLayoutDone = True
self._hasBeenInitalized = False
return True
def Command(self, id, msg):
if id==self.BTN_OK or id==c4d.IDC_OK:
self.print_msg1 = self.GetBool(self.CHKBX1)
self.print_msg2 = self.GetBool(self.CHKBX2)
self.print_msg3 = self.GetBool(self.CHKBX3)
self.Run()
return True
def InitValues(self):
if self._hasBeenInitalized is True:
return True
self.SetBool(self.CHKBX1, True)
self._hasBeenInitalized = True
return True
def Run(self):
message = processing().set_nice_message()
print(message)
c4d.EventAdd()
return True
class processing:
dlg = OptionsDialog()
def set_nice_message(self):
""" how can I get values from OptionsDialog() ???
"""
if self.dlg.print_msg1: result = 'Hello world 1'
if self.dlg.print_msg2: result = 'Hello world 2'
if self.dlg.print_msg3: result = 'Hello world 3'
return result
class DialogCommandData(c4d.plugins.CommandData):
dlg = None
def Execute(self, doc):
if self.dlg is None:
self.dlg = OptionsDialog()
return self.dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC,
pluginid=PLUGIN_ID,
xpos=-2, ypos=-2, defaultw=720, defaulth=50)
def RestoreLayout(self, secret):
if self.dlg is None:
self.dlg = OptionsDialog()
return self.dlg.Restore(pluginid=PLUGIN_ID, secret=secret)
if __name__ == '__main__':
myPlugin = DialogCommandData()
c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID,
str=pluginName,
info=0,
icon=None,
help=pluginName,
dat=myPlugin)
Hey Ferdinand, thank you very much for your time. I really appreciate that!
A custom GUI is so much easier, that I think my whole script is gonna be much shorter and with a pretty nice new functionality.
Cheers
I have a gui.GeDialog with a few Edit Text boxes and I wanted to drop textures from my Windows Explorer on there and get the full path of each texture, just like in the texture field on a material.
I found a couple of useful posts approaching the same question, but the solution seems to be directed to more experienced Python users, as they have only parts of code, not a full working example.
I'd appreciate if someone could share an example on how to do that in this dialog here:
import c4d
class MyDialog(c4d.gui.GeDialog):
def CreateLayout(self):
self.AddEditText(1000, c4d.BFH_SCALEFIT, initw=0, inith=0)
self.AddEditText(1001, c4d.BFH_SCALEFIT, initw=0, inith=0)
self.AddEditText(1002, c4d.BFH_SCALEFIT, initw=0, inith=0)
self.AddEditText(1003, c4d.BFH_SCALEFIT, initw=0, inith=0)
return True
def main():
dialog = MyDialog()
dialog.Open(dlgtype=c4d.DLG_TYPE_MODAL_RESIZEABLE, defaultw=500, defaulth=500)
if __name__ == '__main__':
main()