@John_Do said in CommandData.Message() implementation and Message concepts:
seasoned
baselislienhanMO
@John_Do said in CommandData.Message() implementation and Message concepts:
seasoned
baselislienhanMO
In short,I found out that Place tool's elements is unable to drag and drop into the Python console edit field. So is there anyway to get/set the place tool like the move tool?

I tried using a timer to solve this problem, but I still want to know if there is a more direct way
import c4d
import threading
from c4d.gui import GeUserArea, GeDialog
GADGET_ID_GEUSERAREA = 10000
class DropArea(GeUserArea):
def __init__(self):
# Used to store all objects involved in the drag-and-drop operation
self.currentDragObjects = []
# Flag to indicate whether a drag operation is in progress
self.isDragging = False
# Define a timer to delay the handling of the drag completion
self.dragTimer = None
def Message(self, msg, result):
# Handle drag-and-drop messages
if msg.GetId() == c4d.BFM_DRAGRECEIVE:
# Check if the drag was lost or canceled
if msg.GetInt32(c4d.BFM_DRAG_LOST) or msg.GetInt32(c4d.BFM_DRAG_ESC):
self.isDragging = False
return self.SetDragDestination(c4d.MOUSE_FORBIDDEN)
# If the drag just started, clear the previous object list
if not self.isDragging:
self.currentDragObjects = [] # Initialize the storage list
self.isDragging = True # Mark the beginning of the drag
# Verify if it is a valid drop area
if not self.CheckDropArea(msg, True, True):
return self.SetDragDestination(c4d.MOUSE_FORBIDDEN)
# Get the dragged file object
dragInfo = self.GetDragObject(msg)
if dragInfo is not None:
dragObject = dragInfo['object']
# Check if the object already exists in the list to avoid duplicates
if dragObject not in self.currentDragObjects:
self.currentDragObjects.append(dragObject)
# Reset the timer to delay the handling of drag completion
if self.dragTimer is not None:
self.dragTimer.cancel()
# Set a short timer (e.g., 0.2 seconds) to determine if the drag operation is complete
self.dragTimer = threading.Timer(0.2, self._finalize_drag)
self.dragTimer.start()
# Set the mouse cursor to a valid state
return self.SetDragDestination(c4d.MOUSE_MOVE)
# Call the base class Message() method to handle other messages
return c4d.gui.GeUserArea.Message(self, msg, result)
def _finalize_drag(self):
# Delayed execution to ensure all dragged objects have been received
self.isDragging = False
if self.currentDragObjects:
# Print all dropped files
print(f"Dropped files: {self.currentDragObjects}")
# Additional logic can be executed here, e.g., handling file paths or other content
# Clear the object list for the next drag-and-drop operation
self.currentDragObjects = []
# Redraw the user area (if UI update is needed)
self.Redraw()
class ExampleDialog(GeDialog):
geUserArea = DropArea()
def CreateLayout(self):
self.SetTitle("Drag Area")
if self.GroupBegin(0, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, cols=1, rows=0, title="", groupflags=0, initw=100, inith=100):
self.GroupBorderSpace(8, 8, 8, 8)
self.GroupSpace(2, 2)
# Add the user area gadget
self.AddUserArea(GADGET_ID_GEUSERAREA, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 200, 200)
# Attach the user area to the gadget
self.AttachUserArea(self.geUserArea, GADGET_ID_GEUSERAREA)
self.GroupEnd()
return True
if __name__ == "__main__":
global dlg
dlg = ExampleDialog()
dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC, defaultw=200, defaulth=200)
Hi @Dunhou ,Hi @m_adam , thank you for providing the code. I have also been researching drag and drop methods in GeUserArea recently. I noticed that in the DragObject () method, when retrieving an external file, a single file path is returned. May I ask if it is possible to return a list containing multiple file paths when dragging multiple external files at the same time, similar to the DRAGTYPE-ATOMARRAY
I found the AddPorts() Method,Sorry I missed it before.
from typing import Optional
import c4d
import maxon
doc: c4d.documents.BaseDocument # The active document
op: Optional[c4d.BaseObject] # The active object, None if unselected
def main() -> None:
material = doc.GetActiveMaterial()
nodeMaterial = material.GetNodeMaterialReference()
graph: maxon.GraphModelInterface = nodeMaterial.GetGraph(c4d.GetActiveNodeSpaceId())
with graph.BeginTransaction() as transaction:
layered_node = graph.AddChild(maxon.Id(),"com.chaos.vray_node.texlayeredmax")
layers = layered_node.GetInputs().FindChild("com.chaos.vray_node.texlayeredmax.texture_layers") #The Layers portbundle
layers.AddPorts(2, 1) #Add layers
transaction.Commit()
#Layer in Layers portbundle
layers_list = []
layers.GetChildren(layers_list,maxon.NODE_KIND.INPORT)
#Textureports and BlendMode_ports in Layers portbundle
layers_texport_list = [tport for port in layers_list if (tport := port.FindChild("com.chaos.vray.portbundle.texture_layer.texture"))]
layers_mode_list = [mport for port in layers_list if (mport := port.FindChild("com.chaos.vray.portbundle.texture_layer.blend_mode"))]
print(layered_node)
print(layers)
print(layers_list)
print(layers_texport_list)
print(layers_mode_list)
if __name__ == '__main__':
main()
Hi! @i_mazlov ,
Thanks for your reply,I will take a look at the Forum and Support Guidelines.
About the question
Is there any other way to 'add layer' to the node other than ‘’press‘’ the button?
As shown in the following screenshot.

It's Vray NodeMaterial in the picture,but I found the same structure in scene_root Node and the C4D NodeMaterial.
I had tried GraphNode.SetValue and GraphNode.SetDefaultValue.but I don't know how to set the "value" because it's a Array<Tuple<Id, DataDictionary>> Type.
I did write some codes and I know that they are wrong.But I dont know how to correct it.
from typing import Optional
import c4d
import maxon
doc: c4d.documents.BaseDocument # The active document
op: Optional[c4d.BaseObject] # The active object, None if unselected
def main() -> None:
material = doc.GetActiveMaterial()
nodeMaterial = material.GetNodeMaterialReference()
graph: maxon.GraphModelInterface = nodeMaterial.GetGraph(c4d.GetActiveNodeSpaceId())
layered_list = []
maxon.GraphModelHelper.FindNodesById(graph,"com.chaos.vray_node.texlayeredmax.texture_layers",maxon.NODE_KIND.INPORT, maxon.PORT_DIR.INPUT, False, layered_list)
layered_node = layered_list[0]
with graph.BeginTransaction() as transaction:
data_dict:maxon.DataDictionary = {}
key = "net.maxon.node.attribute.insertindex"
value = 1
data_dict[key] = value
tuple_l = ["_0",data_dict]
array = {tuple_l}
layered_node.SetDefaultValue(array)
transaction.Commit()
print(tuple_l)
if __name__ == '__main__':
main()
thanks.