SOLVED How to delete obj in the environment from a button in userdata

Can someone help me? I would like to be able to activate a button from userdata, and this delete an object or layer, it would help me a lot if they solve my doubt

Hi,

welcome to the forum and community! And thank you for tagging your posting! I only moved your posting into the correct forum.

Your question is a bit broad, so I picked some conditions under which to answer it. First of all I assume here that you are in the environment of one of the embedded Python objects, e.g., a Python generator. In case you are not, and in some form of NodeData plugin, the example below will translate almost directly.

In principle you have to listen to the message send to the node, in case of a Python Generator object or a Python Programming tag with the message() function, in case of a NodeData plugin with your implementation of the NodeData.Message() method. Then you have to sort out if the message is of type MSG_DESCRIPTION_COMMAND and sort out the DescId of the sender. You will find a scene file and a code example below.

I hope this helps and cheers,
Ferdinand

The file:
delete_first_object.c4d

The code:

""" Example for listening for button clicks in a node.

As discussed in:
    https://plugincafe.maxon.net/topic/13251
"""

import c4d

def main():
    """
    """
    pass

def message(mid, data):
    """Retrieves messages sent to the node.

    Messages are used in Cinema 4D to convey event-like information. In this
    case we are listening for the buttons. The setup assumes there to be a 
    button with the user data id 1.

    Args:
        mid (int): The message id.
        data (Any): The message data.

    Returns:
        Any: Depends on the message type.
    """
    # Test if this is a description command message, i.e. a message sent by
    # one of our interface buttons.
    if mid is c4d.MSG_DESCRIPTION_COMMAND:
        # Interface elements are identified in Cinema with something called
        # DescId which is basically just a collection of IDs to identify
        # attributes of a node. DescId are organized in up to three 
        # DescLevels. The relative position of an object is for example 
        # identified by this DescId:
        # 
        #   c4d.DescId(id1=c4d.DescLevel(c4d.ID_BASEOBJECT_REL_POSITION))
        # 
        # Just the x component of that vector is represented like this:
        # 
        #   c4d.DescId(id1=c4d.DescLevel(c4d.ID_BASEOBJECT_REL_POSITION),
        #              id2=c4d.DescLevel(c4d.VECTOR_X)) 
        # 
        # So we have two level in this id, a first one that indicates it is
        # part of the relative position parameter and a second one which 
        # specifies that we only want to address the x-component of that 
        # vector.
        # 
        # For user data the organization is important, because all user data
        # in the parameter name space of an object lives under the first
        # DescLevel of ID_USERDATA (or 700 as an integer). The second 
        # DescLevel is then the user data ID like seen in the user data 
        # manger. To access the x-component of a vector that is an user data
        # element, we can use the third DescLevel, i.e., something like
        # (c4d.ID_USERDATA, 1, c4d.VECTOR_X) when the first user data element
        # is a vector.

        # In case of a MSG_DESCRIPTION_COMMAND message the DescID of the 
        # parameter that raised that message, in this case the button which
        # has been pressed by the user, is being sent with the message data
        # under the key "id".
        if not isinstance(data, dict) or "id" not in data:
            raise RuntimeError("Malformed message data.")
        senderDescId = data["id"]

        # Now we have just to check if this message has actually been sent
        # by the user data button with the ID 1.
        if senderDescId[0].id == c4d.ID_USERDATA and senderDescId[1].id == 1:
            print ("User data button with the id 1 has been pressed.")
            # Get the first object in the scene and delete it.
            node = doc.GetFirstObject()
            # If either the first node is None (which should not happen, 
            # because at least the node executing this code has to be in the 
            # scene) or the first node is the python generator, then bail.
            # The second part is of course optional, but we probably do not
            # want to delete ourselves. It is important here to compare for
            # equality and not for identity due to how Cinema handles nodes
            # (i.e., node == op and not node is op, the latter will always be
            # False).
            if node is None or node == op:
                return True

            # Create an undo so the user can revert the action.
            doc.StartUndo()
            doc.AddUndo(c4d.UNDOTYPE_DELETE, node, )
            # Delete the node, including its children.
            node.Remove()
            # Update Cinema 4D.
            doc.EndUndo()
            c4d.EventAdd()

    return True

Hi,

welcome to the forum and community! And thank you for tagging your posting! I only moved your posting into the correct forum.

Your question is a bit broad, so I picked some conditions under which to answer it. First of all I assume here that you are in the environment of one of the embedded Python objects, e.g., a Python generator. In case you are not, and in some form of NodeData plugin, the example below will translate almost directly.

In principle you have to listen to the message send to the node, in case of a Python Generator object or a Python Programming tag with the message() function, in case of a NodeData plugin with your implementation of the NodeData.Message() method. Then you have to sort out if the message is of type MSG_DESCRIPTION_COMMAND and sort out the DescId of the sender. You will find a scene file and a code example below.

I hope this helps and cheers,
Ferdinand

The file:
delete_first_object.c4d

The code:

""" Example for listening for button clicks in a node.

As discussed in:
    https://plugincafe.maxon.net/topic/13251
"""

import c4d

def main():
    """
    """
    pass

def message(mid, data):
    """Retrieves messages sent to the node.

    Messages are used in Cinema 4D to convey event-like information. In this
    case we are listening for the buttons. The setup assumes there to be a 
    button with the user data id 1.

    Args:
        mid (int): The message id.
        data (Any): The message data.

    Returns:
        Any: Depends on the message type.
    """
    # Test if this is a description command message, i.e. a message sent by
    # one of our interface buttons.
    if mid is c4d.MSG_DESCRIPTION_COMMAND:
        # Interface elements are identified in Cinema with something called
        # DescId which is basically just a collection of IDs to identify
        # attributes of a node. DescId are organized in up to three 
        # DescLevels. The relative position of an object is for example 
        # identified by this DescId:
        # 
        #   c4d.DescId(id1=c4d.DescLevel(c4d.ID_BASEOBJECT_REL_POSITION))
        # 
        # Just the x component of that vector is represented like this:
        # 
        #   c4d.DescId(id1=c4d.DescLevel(c4d.ID_BASEOBJECT_REL_POSITION),
        #              id2=c4d.DescLevel(c4d.VECTOR_X)) 
        # 
        # So we have two level in this id, a first one that indicates it is
        # part of the relative position parameter and a second one which 
        # specifies that we only want to address the x-component of that 
        # vector.
        # 
        # For user data the organization is important, because all user data
        # in the parameter name space of an object lives under the first
        # DescLevel of ID_USERDATA (or 700 as an integer). The second 
        # DescLevel is then the user data ID like seen in the user data 
        # manger. To access the x-component of a vector that is an user data
        # element, we can use the third DescLevel, i.e., something like
        # (c4d.ID_USERDATA, 1, c4d.VECTOR_X) when the first user data element
        # is a vector.

        # In case of a MSG_DESCRIPTION_COMMAND message the DescID of the 
        # parameter that raised that message, in this case the button which
        # has been pressed by the user, is being sent with the message data
        # under the key "id".
        if not isinstance(data, dict) or "id" not in data:
            raise RuntimeError("Malformed message data.")
        senderDescId = data["id"]

        # Now we have just to check if this message has actually been sent
        # by the user data button with the ID 1.
        if senderDescId[0].id == c4d.ID_USERDATA and senderDescId[1].id == 1:
            print ("User data button with the id 1 has been pressed.")
            # Get the first object in the scene and delete it.
            node = doc.GetFirstObject()
            # If either the first node is None (which should not happen, 
            # because at least the node executing this code has to be in the 
            # scene) or the first node is the python generator, then bail.
            # The second part is of course optional, but we probably do not
            # want to delete ourselves. It is important here to compare for
            # equality and not for identity due to how Cinema handles nodes
            # (i.e., node == op and not node is op, the latter will always be
            # False).
            if node is None or node == op:
                return True

            # Create an undo so the user can revert the action.
            doc.StartUndo()
            doc.AddUndo(c4d.UNDOTYPE_DELETE, node, )
            # Delete the node, including its children.
            node.Remove()
            # Update Cinema 4D.
            doc.EndUndo()
            c4d.EventAdd()

    return True
This post is deleted!

Hello @JH23,

without any further feedback or questions, we will consider this topic as solved by Wednesday and flag it accordingly.

Thank you for your understanding,
Ferdinand