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: 

Javascript add-in to modify user parameters

4 REPLIES 4
Reply
Message 1 of 5
piotrH8NPC
625 Views, 4 Replies

Javascript add-in to modify user parameters

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: 

 

  1. onInputChanged function is called with the value from UI inputs
  2. The new value of parameter expression is being applied
  3. After onInputChanged function finishes previous user parameters values are being restored

All of these are illustrated in images I've attached: 

  • step1.png - before applying the new value the dimension in the upper edge of the screenshot is 10mm
  • step2.png - after updating the parameter's expression new value is applied and the value of the dimension in the upper edge applies and is 20mm
  • step3.png - after the function exits the dimension returns to 10mm

 

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?

4 REPLIES 4
Message 2 of 5
marshaltu
in reply to: piotrH8NPC

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()))


Marshal Tu
Fusion 360 Developer
Autodesk, Inc.

Message 3 of 5
prainsberry
in reply to: piotrH8NPC

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.

 



Patrick Rainsberry
Developer Advocate, Fusion 360
Message 4 of 5
piotrH8NPC
in reply to: prainsberry

Thank you 

 

Message 5 of 5
prainsberry
in reply to: piotrH8NPC

Thanks man, glad to help out. Feel free to use this code as needed.

Regards,
Patrick Rainsberry


Patrick Rainsberry
Developer Advocate, Fusion 360

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

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report