ExecutePreview will occur

ExecutePreview will occur

kandennti
Mentor Mentor
801 Views
6 Replies
Message 1 of 7

ExecutePreview will occur

kandennti
Mentor
Mentor

Hi there.

 

The following sample creates a sphere when a point in the sketch is selected.

In MyCommandCreatedHandler, SelectionCommandInput.setSelectionLimits is set to "2", but ExecutePreview occurs even when only one point is selected.
Also, Command.isExecutedWhenPreEmpted = True does not leave any execution results.

1.png

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core

_app: adsk.core.Application = None
_ui: adsk.core.UserInterface = None

_handlers = []

def run(context):
    try:
        global _app, _ui
        _app = adsk.core.Application.get()
        _ui = _app.userInterface

        cmdDef: adsk.core.CommandDefinition = _ui.commandDefinitions.itemById(
            'test_cmd_id'
        )

        if not cmdDef:
            cmdDef = _ui.commandDefinitions.addButtonDefinition(
                'test_cmd_id',
                'test',
                'test'
            )

        global _handlers
        onCommandCreated = MyCommandCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        _handlers.append(onCommandCreated)

        cmdDef.execute()

        adsk.autoTerminate(False)

    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args: adsk.core.CommandCreatedEventArgs):
        adsk.core.Application.get().log(args.firingEvent.name)
        try:
            global _handlers

            cmd: adsk.core.Command = adsk.core.Command.cast(args.command)
            cmd.isExecutedWhenPreEmpted = True # It's not working.

            # event
            onDestroy = MyCommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)

            onExecutePreview = MyExecutePreviewHandler()
            cmd.executePreview.add(onExecutePreview)
            _handlers.append(onExecutePreview)

            # inputs
            inputs: adsk.core.CommandInputs = cmd.commandInputs

            selIpt: adsk.core.SelectionCommandInput = inputs.addSelectionInput(
                'selIpt',
                'Select Scetch Points',
                'Select Scetch Points'
            )
            selIpt.addSelectionFilter('SketchPoints')
            selIpt.setSelectionLimits(2) # Limit is 2 or more.

        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class MyExecutePreviewHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.CommandEventArgs):
        adsk.core.Application.get().log(args.firingEvent.name)

        selIpt: adsk.core.SelectionCommandInput = args.command.commandInputs.itemById(
            'selIpt')

        pnts = [selIpt.selection(idx).entity.worldGeometry for idx in range(
            selIpt.selectionCount)]

        createSphereBodies(pnts)


def createSphereBodies(pnts: list):
    radius = 1

    tmpMgr: adsk.fusion.TemporaryBRepManager = adsk.fusion.TemporaryBRepManager.get()

    sphereBodies: list = []
    pnt: adsk.core.Point3D
    for pnt in pnts:
        sphere: adsk.fusion.BRepBody = tmpMgr.createSphere(pnt, radius)
        sphereBodies.append(sphere)

    app: adsk.core.Application = adsk.core.Application.get()
    des: adsk.fusion.Design = app.activeProduct
    root: adsk.fusion.Component = des.rootComponent

    isParametric: bool = True
    if des.designType == adsk.fusion.DesignTypes.DirectDesignType:
        isParametric = False

    occ: adsk.fusion.Occurrence = root.occurrences.addNewComponent(
        adsk.core.Matrix3D.create()
    )

    comp: adsk.fusion.Component = occ.component

    baseFeat: adsk.fusion.BaseFeature = None
    if isParametric:
        baseFeat = comp.features.baseFeatures.add()

    bodies: adsk.fusion.BRepBodies = comp.bRepBodies

    if isParametric:
        baseFeat.startEdit()
        for body in sphereBodies:
            bodies.add(body, baseFeat)
        baseFeat.finishEdit()
    else:
        for body in sphereBodies:
            bodies.add(body)


class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args: adsk.core.CommandEventArgs):
        adsk.core.Application.get().log(args.firingEvent.name)

        adsk.terminate()

 

0 Likes
802 Views
6 Replies
Replies (6)
Message 2 of 7

j.han97
Advocate
Advocate

Hi @kandennti ,

 

My understanding is: executePreview handler does not actually do any action. In your code, there is no execute handler, therefore the API is not doing any change to the component. You need an execute handler to perform the actions.

 

If you add an execute handler (which does exactly the same thing as in the executePreview handler) as below:

 

class MyExecuteHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        adsk.core.Application.get().log(args.firingEvent.name)

        selIpt: adsk.core.SelectionCommandInput = args.command.commandInputs.itemById(
            'selIpt')

        pnts = [selIpt.selection(idx).entity.worldGeometry for idx in range(
            selIpt.selectionCount)]

        createSphereBodies(pnts)

 

 The script works just fine on my side.

 

Of course the script looks repeated after adding this. You can organize or restructure the code for more reusability. 

Message 3 of 7

j.han97
Advocate
Advocate

In addition, I guess that the executePreview handler will not validate the inputs. Therefore, even if the selections count was under the specified limit, the executePreview handler still did its job. You can add a validation manually by checking the numbers of the selections (although this is not ideal).

Message 4 of 7

BrianEkins
Mentor
Mentor

Is this something you've just discovered or is this something that was working before and is now broken?

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
0 Likes
Message 5 of 7

kandennti
Mentor
Mentor

Thanks for the reply.

 

@j.han97 .

I was wrong about the isExecutedWhenPreEmpted property.
If you set CommandEventHandler.isValidResult = True, you can exit with the preview intact, so you don't need the execute event handler.

class MyExecutePreviewHandler(adsk.core.CommandEventHandler):
・・・
        createSphereBodies(pnts)

        args.isValidResult = True # add

 

@BrianEkins 

This may be my mistake.
I thought the preview was triggered when the "OK" button was enabled, is that wrong?

 

Message 6 of 7

BrianEkins
Mentor
Mentor

ExecutePreview is fired every time any of the command inputs are modified. This allows you to create a new preview based on the current input settting.

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 7 of 7

kandennti
Mentor
Mentor

Thanks, @BrianEkins .

 

Modified MyCommandCreatedHandler to add the validateInputs event.

・・・
class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args: adsk.core.CommandCreatedEventArgs):
        adsk.core.Application.get().log(args.firingEvent.name)
        try:
            global _handlers

            cmd: adsk.core.Command = adsk.core.Command.cast(args.command)
            cmd.isExecutedWhenPreEmpted = False

            # event
            onDestroy = MyCommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)

            onExecutePreview = MyExecutePreviewHandler()
            cmd.executePreview.add(onExecutePreview)
            _handlers.append(onExecutePreview)

            onValidateInputs = MyValidateInputsHandler()
            cmd.validateInputs.add(onValidateInputs)
            _handlers.append(onValidateInputs)

            # inputs
            inputs: adsk.core.CommandInputs = cmd.commandInputs

            selIpt: adsk.core.SelectionCommandInput = inputs.addSelectionInput(
                'selIpt',
                'Select Scetch Points',
                'Select Scetch Points'
            )
            selIpt.addSelectionFilter('SketchPoints')
            selIpt.setSelectionLimits(2) # Limit is 2 or more.

        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class MyValidateInputsHandler(adsk.core.ValidateInputsEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.ValidateInputsEventArgs):
        adsk.core.Application.get().log(args.firingEvent.name)

        selIpt: adsk.core.SelectionCommandInput = args.inputs.itemById('selIpt')
        limits = selIpt.getSelectionLimits()
        if selIpt.selectionCount < limits[1]:
            args.areInputsValid = False

class MyExecutePreviewHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.CommandEventArgs):
        adsk.core.Application.get().log(args.firingEvent.name)

        selIpt: adsk.core.SelectionCommandInput = args.command.commandInputs.itemById(
            'selIpt')

        pnts = [selIpt.selection(idx).entity.worldGeometry for idx in range(
            selIpt.selectionCount)]

        createSphereBodies(pnts)

        args.isValidResult = True
・・・

 

In MyValidateInputsHandler, I just changed the areInputsValid property. My understanding is that the property is used to enable/disable the OK button, not to directly adjust the firing of the executePreview event.
As a result, when the OK button is disabled, the executePreview event is not fired, so I thought the OK button was the executePreview event trigger.

 

Now, I feel the need to always use the validateInputs event when using SelectionCommandInput.

 

0 Likes