Community
Fusion API and Scripts
Got a new add-in to share? Need something specialized to be scripted? Ask questions or share what you’ve discovered with the community.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Creating a custom command dialog then running a text command causes Fusion 360 to crash

9 REPLIES 9
Reply
Message 1 of 10
jphalip
376 Views, 9 Replies

Creating a custom command dialog then running a text command causes Fusion 360 to crash

Hi,

 

I'm writing a script that creates a custom command dialog to prompt the user to enter some information. Then when the user clicks OK, the script needs to run a text command to create a Coil based on the information entered by the user in the previous dialog. The issue is that this workflow causes Fusion 360 to crash.

 

It looks like maybe there is some issue with the second command dialog (the created with a "Commands.Start" text command) clashes with the previous command dialog. Should the first command maybe cleaned up somehow before running the second one?

 

I've created the following bare-bone script to reproduce the issue. Warning: if you run this as-is then it'll likely crash Fusion 360 as it does for me. It is specifically the last line ("app.executeTextCommand(u'Commands.Start Extrude')") that causes the crash.

 

Do you know what's causing this and how to fix it or work around it?

 

Thanks!

 

Julien

 

import adsk.core, adsk.fusion, traceback

app = adsk.core.Application.get()
ui = app.userInterface
handlers = []


def run(context):
    cmdDef = ui.commandDefinitions.itemById('myCmd')
    if not cmdDef:
        cmdDef = ui.commandDefinitions.addButtonDefinition('myCmd', 'myCmd', 'myCmd')
    onCommandCreated = MyCommandCreatedHandler()
    cmdDef.commandCreated.add(onCommandCreated)
    handlers.append(onCommandCreated)
    cmdDef.execute()
    adsk.autoTerminate(False)


class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def notify(self, args):
        adsk.terminate()


class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def notify(self, args):
        cmd = adsk.core.Command.cast(args.command)
        onExecute = MyCommandExecuteHandler()
        cmd.execute.add(onExecute)
        handlers.append(onExecute)
        onDestroy = MyCommandDestroyHandler()
        cmd.destroy.add(onDestroy)
        handlers.append(onDestroy)
        inputs: adsk.core.CommandInputs = cmd.commandInputs
        inputs.addTextBoxCommandInput('my_text', 'Some text', 'abcd', 1, False)


class MyCommandExecuteHandler(adsk.core.CommandEventHandler):
    def notify(self, args):
        # WARNING: Starting a new text command causes Fusion 360 to crash
        app.executeTextCommand(u'Commands.Start Coil')

  

9 REPLIES 9
Message 2 of 10
kandennti
in reply to: jphalip

Hi @jphalip .

 

Perhaps there is no one to answer the text command question.
There is no other way but to try various things that come to mind.

 

I have a similar experience with text commands. At that time, I gave up using dialogs.

 

When I run the coil command in the GUI, several commands are executed before "Coil" is executed.

1.png

 

When we tried it here, we were able to handle it by drawing a sketch circle in advance and making it selected, but when we used the dialog, it crashed as well.

 

The only way to deal with this may be to use sweeps.

Message 3 of 10
jphalip
in reply to: jphalip

Thanks @kandennti. I think I managed to get it to work and avoid the crash by registering another handler (ui.commandTerminated) to wait until my custom command is fully terminated before calling the Coil text command. See the bare-bone code sample below. I'll now try to transfer that to my real code and hopefully it'll work as I need it to.


 

import adsk.core, adsk.fusion, traceback

app = adsk.core.Application.get()
ui = app.userInterface
handlers = {}
results: dict = {}
commandId: str = 'myCmd'
command: adsk.core.Command = None


def run(context):
    cmdDef = ui.commandDefinitions.itemById(commandId)
    if not cmdDef:
        cmdDef = ui.commandDefinitions.addButtonDefinition(commandId, '', '')
    handlers['commandCreated'] = MyCommandCreatedHandler()
    cmdDef.commandCreated.add(handlers['commandCreated'])
    cmdDef.execute()
    adsk.autoTerminate(False)


class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def notify(self, args):
        adsk.terminate()


class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def notify(self, args):
        global command
        command = args.command

        # Create the event handlers
        handlers['execute'] = MyCommandExecuteHandler()
        command.execute.add(handlers['execute'])
        handlers['destroy'] = MyCommandDestroyHandler()
        command.destroy.add(handlers['destroy'])
        handlers['terminate'] = MyCommandTerminateHandler()
        ui.commandTerminated.add(handlers['terminate'])

        # Create the command inputs
        inputs: adsk.core.CommandInputs = command.commandInputs
        inputs.addTextBoxCommandInput('my_text', 'Some text', 'abcd', 1, False)


class MyCommandExecuteHandler(adsk.core.CommandEventHandler):
    def notify(self, args: adsk.core.CommandEventArgs):
        # This gets called after the user clicks OK in the custom command
        command: adsk.core.Command = args.firingEvent.sender
        inputs = command.commandInputs
        # Store the command results
        results['my_text'] = inputs.itemById('my_text').text


class MyCommandTerminateHandler(adsk.core.ApplicationCommandEventHandler):
    def notify(self, args:adsk.core.ApplicationCommandEventArgs):
        # This gets called after the command has been fully terminated
        if args.commandId == commandId and 'my_text' in results:
            # Deactivate all the event handlers
            command.execute.remove(handlers['execute'])
            command.destroy.remove(handlers['destroy'])
            ui.commandTerminated.remove(handlers['terminate'])
            ui.commandDefinitions.itemById(commandId).commandCreated.remove(handlers['commandCreated'])
            handlers.clear()

            # Call another text command
            app.executeTextCommand(u'Commands.Start Coil')

 

Message 4 of 10
jphalip
in reply to: jphalip

Quick update: My script now works all the way to the end... except that If I then try to modify any of the created features by double-clicking it in the timeline, then Fusion 360 crashes. Seems like a bug to me. This is so frustrating 😞

Message 5 of 10
kandennti
in reply to: jphalip

@jphalip .

 

I don't know what the end goal is, but if creating the coil is the last process and it is ok to display the dialog, it would be easier to use the CommandDefinition.execute method.

class MyCommandExecuteHandler(adsk.core.CommandEventHandler):
    def notify(self, args):
        coilCmdDef: adsk.core.CommandDefinition = ui.commandDefinitions.itemById(
            'Coil'
        )

        if not coilCmdDef:
            return

        coilCmdDef.execute()
Message 6 of 10
jphalip
in reply to: kandennti

@kandennti Thank you. Unfortunately, I need to create more features after the coil.

 

I've added the Coil creation script you had provided here to the bare-bone example. Running this script reliably crashes Fusion 360 for me...

 

import adsk.core, adsk.fusion, traceback
import math

app = adsk.core.Application.get()
ui = app.userInterface
design: adsk.fusion.Design = app.activeProduct
root: adsk.fusion.Component = design.rootComponent
handlers = {}
results: dict = {}
commandId: str = 'myCmd'
command: adsk.core.Command = None


def run(context):
    cmdDef = ui.commandDefinitions.itemById(commandId)
    if not cmdDef:
        cmdDef = ui.commandDefinitions.addButtonDefinition(commandId, '', '')
    handlers['commandCreated'] = MyCommandCreatedHandler()
    cmdDef.commandCreated.add(handlers['commandCreated'])
    cmdDef.execute()
    adsk.autoTerminate(False)


class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def notify(self, args):
        adsk.terminate()


class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def notify(self, args):
        global command
        command = args.command

        # Create the event handlers
        handlers['execute'] = MyCommandExecuteHandler()
        command.execute.add(handlers['execute'])
        handlers['destroy'] = MyCommandDestroyHandler()
        command.destroy.add(handlers['destroy'])
        handlers['terminate'] = MyCommandTerminateHandler()
        ui.commandTerminated.add(handlers['terminate'])

        # Create the command inputs
        inputs: adsk.core.CommandInputs = command.commandInputs
        inputs.addTextBoxCommandInput('my_text', 'Some text', 'abcd', 1, False)


class MyCommandExecuteHandler(adsk.core.CommandEventHandler):
    def notify(self, args: adsk.core.CommandEventArgs):
        # This gets called after the user clicks OK in the custom command
        command: adsk.core.Command = args.firingEvent.sender
        inputs = command.commandInputs
        # Store the command results
        results['my_text'] = inputs.itemById('my_text').text


class MyCommandTerminateHandler(adsk.core.ApplicationCommandEventHandler):
    def notify(self, args:adsk.core.ApplicationCommandEventArgs):
        # This gets called after the command has been fully terminated
        if args.commandId == commandId and 'my_text' in results:
            # Deactivate all the event handlers
            command.execute.remove(handlers['execute'])
            command.destroy.remove(handlers['destroy'])
            ui.commandTerminated.remove(handlers['terminate'])
            ui.commandDefinitions.itemById(commandId).commandCreated.remove(handlers['commandCreated'])
            handlers.clear()

            coilFeat: adsk.fusion.CoilFeature = create_coil(
                root,
                adsk.core.Point3D.create(2, 1, 0),
                1.0,
                4.0,
                3.0,
                15.0,
                0.5
            )

def create_coil(
    comp: adsk.fusion.Component,
    center: adsk.core.Point3D,
    coilDiameter: float,
    coilRevolutions: float,
    coilHeight: float,
    coilTaperAngle_deg: float,
    sectionSize: float):

    skt: adsk.fusion.Sketch = comp.sketches.add(
        comp.xYConstructionPlane
    )
    sktCircles: adsk.fusion.SketchCircles = skt.sketchCurves.sketchCircles

    circle: adsk.fusion.SketchCircle = sktCircles.addByCenterRadius(
        center,
        coilDiameter * 0.5
    )

    comp: adsk.fusion.Component = circle.parentSketch.parentComponent

    app: adsk.core.Application = adsk.core.Application.get()
    ui: adsk.core.UserInterface = app.userInterface

    sels: adsk.core.Selections = ui.activeSelections
    sels.clear()
    sels.add(circle)

    app.executeTextCommand(u'Commands.Start Coil')
    app.executeTextCommand(u'Commands.SetString infoSizeType infoRevolutionAndHeight')
    app.executeTextCommand(u'Commands.SetDouble CoilRevolutions {}'.format(coilRevolutions))
    app.executeTextCommand(u'Commands.SetDouble CoilHeight {}'.format(coilHeight))
    app.executeTextCommand(u'Commands.SetDouble CoilTaperAngle {}'.format(math.radians(coilTaperAngle_deg)))
    app.executeTextCommand(u'Commands.SetString infoSectionType infoCircular')
    app.executeTextCommand(u'Commands.SetString infoSectionPosition infoOutside')
    app.executeTextCommand(u'Commands.SetDouble SectionSize {}'.format(sectionSize))
    app.executeTextCommand(u'Commands.SetString infoBooleanType infoNewBodyType')
    app.executeTextCommand(u'NuCommands.CommitCmd')

    skt.deleteMe()

    return comp.features.coilFeatures[-1]

 

Message 7 of 10
kandennti
in reply to: jphalip

@jphalip .

 

Unfortunately, I can't think of a way to avoid the crash.

Message 8 of 10
jphalip
in reply to: kandennti

@kandennti No worries, I appreciate your help. By chance, do you know what's the best way to report this to the development team as a potential bug?

Message 9 of 10
kandennti
in reply to: jphalip

@jphalip .

 

As I mentioned here, my understanding is that Autodesk does not recommend the use of text commands.

https://github.com/kantoku-code/Fusion360_Small_Tools_for_Developers/tree/master/TextCommands 

 

It is only to be used at your own risk and I don't think it is something that can be directed as a bug.

Message 10 of 10
jphalip
in reply to: kandennti

@kandennti Ok I see. And if I understand correctly, there is no way to create a coil feature other than with text commands, is that right?

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report