Announcements
Attention for Customers without Multi-Factor Authentication or Single Sign-On - OTP Verification rolls out April 2025. Read all about it here.

Components disappear after being created by addBoolValueInput button in Command Dialog

ebunn3
Advocate

Components disappear after being created by addBoolValueInput button in Command Dialog

ebunn3
Advocate
Advocate

Hi,

 

I am putting together an Add-in and having trouble with a button on the form that is designed to create a component when clicked.  It creates the component and some features within the component.   It creates the component/geometry and then it disappears from view.  If I put the same code in the OK button it works.  I want the user to be able to create this geometry without having to close the form.  I didn't post any code since it is quite lengthy and involved but could put together a snippet if need be to demonstrate what is happening.  I understand that anything created with the form is shown as a preview and doesn't stay in the model unless you hit the OK button.  I don't even see a preview.

 

Can anyone tell me how to create features using an addBoolValueInput  button?  

 

Thanks,

 

Eric

0 Likes
Reply
Accepted solutions (1)
469 Views
7 Replies
Replies (7)

j.han97
Advocate
Advocate

Hi,

 

I did something similar before in my addin. From my experience, if you want to preview the changes, the appropriate method is to use the executePreview handler. For other handlers (I tried inputChanged handler), the changes I made disappeared instantly after being created.

 

In your case, maybe you can try using temporaryBRepManager and customGraphicsGroup. If available, a snippet of your code always help others to understand your situation better.

0 Likes

ebunn3
Advocate
Advocate

Thanks for the reply.   I’ll do some digging to see what I can find out about the executePreview Handler.  I’ll also try to put together a sample script.  

Basically I am trying to create a component and insert a bRepBody into it.   I construct a temporary body first and then add it to the component. 

Eric

0 Likes

ebunn3
Advocate
Advocate

I've started building my executePreview Handler (pasted below) and cannot determine how to identify what fired the event .  In my InputChangedEventHandler I can use changedInput = eventArgs.input to determine the input that  triggered the event.  This line of code will not work in the executePreview Handler?  My work around for now is using a global variable to capture it from the input handler since it goes there first.  I want to run my functions when a particular button is pushed and need to identify this in the handler.

 

Thanks for the help.

 

Eric

 

class CommandExecutePreviewHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        app = adsk.core.Application.get()
        ui = app.userInterface
        try:
            eventArgs = adsk.core.CommandEventArgs.cast(args)
            inputs = eventArgs.command.commandInputs
            #global variable to track changed input = changedInputID
            if changedInputID.id =='plotPoints':
                print("do something")
            
            # Set the the preview results can be used as the execute result.
            eventArgs.isValidResult = True
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

0 Likes

j.han97
Advocate
Advocate
Accepted solution

Hi @ebunn3 ,

 

I have made a short sample which should work: 

import adsk.core, adsk.fusion, adsk.cam, traceback
import random

class addBody_commandCreatedEventHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    
    def notify(self, args):
        try:
            #Change to direct design type
            #   Note: If using parametric design type, base feature should be added
            #   base = rootComponent.baseFeatures.add()
            #   base.startEdit() ----> base.finishEdit()
            design = adsk.fusion.Design.cast(_app.activeProduct)
            design.designType = adsk.fusion.DesignTypes.DirectDesignType
            command = adsk.core.CommandCreatedEventArgs.cast(args).command
            inputs = command.commandInputs
            
            #Add a button to add body
            inputs.addBoolValueInput('addBody_button', 'Add', False, '', False)
            #Connect to events
            addBody_inputChanged = addBody_inputChangedHandler()
            command.inputChanged.add(addBody_inputChanged)
            _handlers.append(addBody_inputChanged)

            addBody_executePreview = addBody_executePreviewHandler()
            command.executePreview.add(addBody_executePreview)
            _handlers.append(addBody_executePreview)

            addBody_execute = addBody_executeHandler()
            command.execute.add(addBody_execute)
            _handlers.append(addBody_execute)
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class addBody_inputChangedHandler(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    
    def notify(self, args):
        try:
            global _temp_body, _temp_body_origin
            ipt = adsk.core.InputChangedEventArgs.cast(args).input
            if ipt.id == 'addBody_button':
                #Decide origin for new body
                while True:
                    #Get a random point
                    new_coor = [random.randint(-10, 10), random.randint(-10, 10), random.randint(-10, 10)]
                    if not new_coor in _temp_body_origin:
                        #If not exist, create a point
                        new_origin = adsk.core.Point3D.create(new_coor[0], new_coor[1], new_coor[2])
                        _temp_body_origin
                        break
                
                #Create a 0.5-side cube
                length_dir = adsk.core.Vector3D.create(1, 0, 0)
                width_dir = adsk.core.Vector3D.create(0, 1, 0)
                
                length = 0.5
                width = 0.5
                height = 0.5
                
                #Create oriented bouding box
                obb = adsk.core.OrientedBoundingBox3D.create(new_origin, length_dir, width_dir, length, width, height)

                #Add to new temporary bRepBody
                tempBR_manager = adsk.fusion.TemporaryBRepManager.get()
                temp_body = tempBR_manager.createBox(obb)
                
                _temp_body.append(temp_body)
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class addBody_executePreviewHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    
    def notify(self, args):
        try:
            global _temp_body
            root_comp = adsk.fusion.Design.cast(_app.activeProduct).rootComponent
            cgg = root_comp.customGraphicsGroups.add()
            for temp_body in _temp_body:
                cg_body = cgg.addBRepBody(temp_body)
                #cg_body.color = //color #Add color if desired
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class addBody_executeHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    
    def notify(self, args):
        try:
            global _temp_body
            #Add bodies under rootComponent
            root_comp = adsk.fusion.Design.cast(_app.activeProduct).rootComponent
            for temp_body in _temp_body:
                root_comp.bRepBodies.add(temp_body)
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

_app = adsk.core.Application.get()
_ui  = _app.userInterface
_handlers = []
_temp_body = []; _temp_body_origin = []
        
def run(context):
    try:
        #Get command definitions & design workspace
        cmd_def = _ui.commandDefinitions
        des_wp = _ui.workspaces.itemById('FusionSolidEnvironment')
        
        #Get tools tab
        tools_tab = des_wp.toolbarTabs.itemById('ToolsTab')
        
        #Get add-in panel
        addin_panel = tools_tab.toolbarPanels.itemById('SolidScriptsAddinsPanel')
        
        #Add command definition and control
        addBody_cmdDef = cmd_def.itemById('AddBody_cmd')
        if not addBody_cmdDef:
            addBody_cmdDef = cmd_def.addButtonDefinition('AddBody_cmd', 'Add body', 'Adds body(bodies) to root component', './resources/addBody')
        addBody_ctrl = addin_panel.controls.itemById('AddBody_cmd')
        if not addBody_ctrl:
            addBody_ctrl = addin_panel.controls.addCommand(addBody_cmdDef)
        
        #Set visibility of control
        addBody_ctrl.isVisible = True; addBody_ctrl.isPromoted = True; addBody_ctrl.isPromotedByDefault = True
        
        #Connect to command created event
        addBody_commandCreated = addBody_commandCreatedEventHandler()
        addBody_cmdDef.commandCreated.add(addBody_commandCreated)
        _handlers.append(addBody_commandCreated)
        
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

You will probably need to modify it to suit your case better. You need to put your own icon in the './resources/addBody' folder.

 

Unfortunately, although I personally do not like using global variables, it seems like using global variables is a MUST to pass the data around. In this code, most of the work is done in inputChangedHandler, where a new temporary body is created. The executePreviewHandler shows the temporary body. The preview handler do not have to 'respond' to something (button click), instead, it constantly refreshes itself (it always listens to everything). Finally, the executeHandler adds the body.

 

0 Likes

BrianEkins
Mentor
Mentor

Where is the code that is creating the component?  The code that draws the preview should be in the executePreview event handler.  Whatever you draw in that event will be displayed until any dialog input is changed or the OK or Cancel button is clicked.  Each time you make a change to any input, you need to redraw the entire preview.  When the user clicks OK, that executes the command and the execute event will be fired where you can create the final result.  If the preview and the final are the same things you can set the isValidResult property of the CommandEventArgs object in the executePreview event to True.  In this case, the execute event will be skipped and whatever you created for the preview will be the final result.

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
1 Like

ebunn3
Advocate
Advocate

Brian,

 

That makes total sense.  I wasn't clear on why you needed the onExecute and the onExecutePreview handlers.  Thanks for explaining. 

 

Eric

0 Likes

ebunn3
Advocate
Advocate

Thank you so much for putting this together for me.  I like how you create the temporary body in the input changed handler and then use the preview handler to add the temporary body to the window.  That makes total sense.  Thank you.

 

Eric

0 Likes