Hi
I've been testing out writing a Javascript Add-in which would manipulate user params. Since it's a new environment I've started with the AddInSample javascript code which is bundled with Autodesk Fusion 360 and created new addIn with nearly identical sources to make the UI initialization work. The major modifications I've made are in the onInputChanged function. The current version of the source looks the following way:
var onInputChanged = function(args) { console.log('onInputChanged', args, args.input, args.input.name, '=', args.input.value); var name = args.input.name; var expr = args.input.value; try { var app = adsk.core.Application.get(); var design = app.activeProduct; var userParams = design.userParameters var p = design.userParameters.itemByName(name); p.expression = ''+expr; } catch (e) { ui.messageBox(locStrings.FailedInInputChangedEvent + errorDescription(e)); } };
What I've been struggling with is the runtime behaviour of the code above. To begin with I've defined 2 user parameters and used them to dimension a rectangle in a sketch. When I edit a parameter in the UI of the add in what is happening is the following sequence of events which I've caught with the debugger breakpoint:
All of these are illustrated in images I've attached:
What I'm suspecting is that handling of the userParams manipulation is done in a temporary context/thread and thus it doesn't apply to the activeDocument/design context so it could be persisted. Does somebody maybe know how to persist the new expression value to the design?
Hello,
I would like to recommend you do that in onExecute event instead of onInputChanged. The following Python sample would demostrade what you want. You can translate it to Javascript if you prefer to Javascript language.
In a command, generally we only commit the changes which made in onExecute. For those changes in other events, we will treat it as command preview and abort them right away before onExecute event is executed.
Thanks,
Marshal
#Author- #Description- import adsk.core, adsk.fusion, traceback import os # global set of event handlers to keep them referenced for the duration of the command handlers = [] app = adsk.core.Application.get() if app: ui = app.userInterface class MyCommandExecuteHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): try: command = args.firingEvent.sender inputs = command.commandInputs # We need access to the inputs within a command during the execute. nameInput = inputs.itemById('Name') valInput = inputs.itemById('Value') name = nameInput.value expr = valInput.value design = app.activeProduct p = design.userParameters.itemByName(name) p.expression = '' + expr except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) class MyCommandDestroyHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): try: # when the command is done, terminate the script # this will release all globals which will remove all event handlers adsk.terminate() 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): try: cmd = args.command onExecute = MyCommandExecuteHandler() cmd.execute.add(onExecute) onDestroy = MyCommandDestroyHandler() cmd.destroy.add(onDestroy) # keep the handler referenced beyond this function handlers.append(onExecute) handlers.append(onDestroy) # Define the inputs. inputs = cmd.commandInputs inputs.addStringValueInput('Name', 'Number of Parameter', 'A') inputs.addStringValueInput('Value', 'Value of Parameter', '1 in') except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) def run(context): try: commandId = 'ModifyParameter' commandName = 'Modify parameter' commandDescription = 'Modify parameter' cmdDef = ui.commandDefinitions.itemById(commandId) if not cmdDef: resourceDir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'resources') # absolute resource file path is specified cmdDef = ui.commandDefinitions.addButtonDefinition(commandId, commandName, commandDescription, resourceDir) onCommandCreated = MyCommandCreatedHandler() cmdDef.commandCreated.add(onCommandCreated) # keep the handler referenced beyond this function handlers.append(onCommandCreated) inputs = adsk.core.NamedValues.create() cmdDef.execute(inputs) # prevent this module from being terminate when the script returns, because we are waiting for event handlers to fire adsk.autoTerminate(False) except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
Hey check this example out. I actually use both methods. It is kind of nice to see the parameters update live when you are changing them, then you commit the values in on execute.
hope this helps:
https://github.com/tapnair/ParamEdit
Sorry it is also in Python. BTW if you are going to be doing anythign that involves a lot of actions like updating parameters you will find it significantly faster in python vs. Javascript. JS runs out of process and is orders of magnatude slower to compute. If it is possible for your application.
Thank you prainsberry! This is exactly what I wanted to write in JS as live preview is a really useful feature.