How to prevent ApplicationCommandEventHandler to be called a million times

How to prevent ApplicationCommandEventHandler to be called a million times

lichtzeichenanlage
Advisor Advisor
1,293 Views
8 Replies
Message 1 of 9

How to prevent ApplicationCommandEventHandler to be called a million times

lichtzeichenanlage
Advisor
Advisor

I try to create and close a temporary document within the CommandExecuteHandler which forces Fusion 360 to crash. I search the forum and it looks like that the commandTerminated is the solution to this problem but for me a new problem occurs: The function is called "a million times" and I can't prevent this. So any idea how to solve one the two problems?

 

 

#Author-Author
#Description-Description

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

TOOLBAR_PANEL_ID = 'MyPanel'
TOOLBAR_PANEL_NAME = 'My Name'
MY_COMMAND_ID = "MyCommand"
MY_COMMAND_NAME = "My Command"
MY_COMMAND_TOOLTIP = "My Description"

# Global set of event handlers to keep them referenced for the duration of the command
_handlers = []
handlers = []
_document = None

class CommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            # Get the command that was created.
            cmd = adsk.core.Command.cast(args.command)

            onExecute = CommandExecuteHandler()
            cmd.execute.add(onExecute)
            _handlers.append(onExecute)

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

            onInputChanged = CommandInputChangedHandler()
            cmd.inputChanged.add(onInputChanged)
            _handlers.append(onInputChanged)

            onDestroy = CommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)

            inputs = cmd.commandInputs
            inputs.addTextBoxCommandInput("idasdf","Name","Hello World!", 1, False)
        except:
            app = adsk.core.Application.get()
            ui = app.userInterface
            ui.messageBox(traceback.format_exc())

class CommandExecuteHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            global _document

            app = adsk.core.Application.get()
            activeDocument = app.activeDocument
            ui = app.userInterface

            application = adsk.core.Application.get()
            fusionDocType = adsk.core.DocumentTypes.FusionDesignDocumentType
            _document = application.documents.add(fusionDocType)

            # set design type
            design :adsk.fusion.Design = _document.design
            design.designType = adsk.fusion.DesignTypes.DirectDesignType

            # get root component
            rootComponent :adsk.fusion.Component = design.rootComponent
        except:
            app = adsk.core.Application.get()
            ui = app.userInterface
            ui.messageBox(traceback.format_exc())

class CommandExecutePreviewHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            eventArgs = adsk.core.CommandEventArgs.cast(args)

            eventArgs.isValidResult = False

        except:
            app = adsk.core.Application.get()
            ui = app.userInterface
            ui.messageBox(traceback.format_exc())

class CommandInputChangedHandler(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            pass
        except:
            app = adsk.core.Application.get()
            ui = app.userInterface
            ui.messageBox(traceback.format_exc())

class CommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            pass
        except:
            app = adsk.core.Application.get()
            ui = app.userInterface
            ui.messageBox(traceback.format_exc())

class MyCommandTerminatedHandler(adsk.core.ApplicationCommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        app = adsk.core.Application.get()
        ui = app.userInterface
        eventArgs = adsk.core.ApplicationCommandEventArgs.cast(args)

        global _document

        if _document:
            print("Closing " + _document.name)
            _document.close(False)
            _document = None

def run(context):
    try:
        # create panel
        app = adsk.core.Application.get()
        ui = app.userInterface

        # create panel

        # get toolbarPanels
        allDesignTabs = ui.toolbarTabsByProductType('DesignProductType')
        toolsTab = allDesignTabs.itemById('SolidTab')
        toolbarPanels = toolsTab.toolbarPanels

        # get toolbarPanel
        toolbarPanel = toolbarPanels.itemById(TOOLBAR_PANEL_ID)
        if not toolbarPanel:
            toolbarPanel = toolbarPanels.add(TOOLBAR_PANEL_ID, TOOLBAR_PANEL_NAME, 'SelectPanel', False)

        # create command definition
        commanDefinition = ui.commandDefinitions.itemById(MY_COMMAND_ID)
        if not commanDefinition:
            commanDefinition = ui.commandDefinitions.addButtonDefinition(MY_COMMAND_ID, MY_COMMAND_NAME, MY_COMMAND_TOOLTIP, "")

        # adds the commandDefinition to the toolbar panel
        cmdControl = toolbarPanel.controls.addCommand(commanDefinition)
        cmdControl.isPromotedByDefault = True

        onCommandTerminated = MyCommandTerminatedHandler()
        ui.commandTerminated.add(onCommandTerminated)
        handlers.append(onCommandTerminated)

        # add event handler
        onCommandCreated = CommandCreatedHandler()
        commanDefinition.commandCreated.add(onCommandCreated)

        _handlers.append(onCommandCreated)
    except:
        app = adsk.core.Application.get()
        ui = app.userInterface
        ui.messageBox(traceback.format_exc())

def stop(context):
    try:
        app = adsk.core.Application.get()
        ui = app.userInterface

        # removes the panel from the toolbar
        workSpace = ui.workspaces.itemById('FusionSolidEnvironment')
        toolbarPanels = workSpace.toolbarPanels

        # get toolbarPanel
        toolbarPanel = toolbarPanels.itemById(TOOLBAR_PANEL_ID)
        if  toolbarPanel:
            toolbarPanel.deleteMe()

        # delete the commandDefinition
        commandDefinition = ui.commandDefinitions.itemById(MY_COMMAND_ID)
        if commandDefinition:
            commandDefinition.deleteMe()

        print("Addin stopped")

    except:
        app = adsk.core.Application.get()
        ui = app.userInterface
        ui.messageBox(traceback.format_exc())

 

0 Likes
1,294 Views
8 Replies
Replies (8)
Message 2 of 9

lichtzeichenanlage
Advisor
Advisor

Pull

0 Likes
Message 3 of 9

lichtzeichenanlage
Advisor
Advisor

Pull

0 Likes
Message 4 of 9

lichtzeichenanlage
Advisor
Advisor

Pull

0 Likes
Message 5 of 9

NDeis
Explorer
Explorer

I am also looking at understanding this event call better. Did you figure this out?

0 Likes
Message 6 of 9

lichtzeichenanlage
Advisor
Advisor

Nope. I haven't invested much time into it. 

0 Likes
Message 7 of 9

OceanHydroAU
Collaborator
Collaborator

My guess is that's some kind of logic error - there's a reason for every call, and if you handle them all properly everything works nicely.

0 Likes
Message 8 of 9

NDeis
Explorer
Explorer

Ya the reason for the duplication is the question here.
From the logfile that my particular code generates I can confirm the onCommandStarting event trigger does seem to fire multiple times on most commands. Ie DrawPolyline, SketchStop, Extrude

 

I would like to understand if this is intentional or maybe this event is catching multiple types of interrupts.

0 Likes
Message 9 of 9

kandennti
Mentor
Mentor

Hi @lichtzeichenanlage .

 

I don't think it is possible to suppress the calls to the commandTerminated event.
On the other hand, if we are able to control the calls to it, I feel that it would be meaningless as an event.

 

Instead, I would check the args.commandId at the beginning of the Handler and return immediately if it is irrelevant.

class MyCommandTerminatedHandler(adsk.core.ApplicationCommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            eventArgs = adsk.core.ApplicationCommandEventArgs.cast(args)

            global MY_COMMAND_ID 
            if eventArgs.commandId != MY_COMMAND_ID:
                return

            global _document
            if _document:
                print("Closing " + _document.name)
                _document.close(False)
                _document = None

        except:
            ui = adsk.core.Application.get().userInterface
            ui.messageBox(traceback.format_exc())    

 

However, this did not solve the issue of Fusion360 crashing.

0 Likes