If selector is present then validator won't be called until a selection is made

If selector is present then validator won't be called until a selection is made

adonno
Enthusiast Enthusiast
607 Views
4 Replies
Message 1 of 5

If selector is present then validator won't be called until a selection is made

adonno
Enthusiast
Enthusiast

I have a simple piece of code (listed below) that has a SelectionCommandInput (filtered to require a single sketch line) and an input box where I expect an integer >= 3 to be entered. Following the example in SpurGear, to ensure that I actually get an integer, I created a ValidateInputsEventHandler class, in which I check the input. The thing that is bothering me is that validator only gets called if (and only if) I have already selected a line. If I remove the line selector then the validator gets called as expected.

 

Is this expected or am I doing something wrong.

 

Thanks

Tony 

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

app = adsk.core.Application.cast(None)
ui = adsk.core.UserInterface.cast(None)
handlers = []

# Global variables
ID = 'TV'
MIN_VALUE = 3

# Command inputs
_selected_line = adsk.core.SelectionCommandInput.cast(None)
_number = adsk.core.StringValueCommandInput.cast(None)
_err_message = adsk.core.StringValueCommandInput.cast(None)

def run(context):
    try:
        global app, ui, handlers
        
        app = adsk.core.Application.get()
        ui  = app.userInterface

        # Get the existing command definition or create it if it doesn't already exist.
        cmd_def = ui.commandDefinitions.itemById('TestValidation')
        if not cmd_def:
            cmd_def = ui.commandDefinitions.addButtonDefinition('TestValidation', 
                                                                'Test Validation', 
                                                                'Sample to demonstrate validaiton')
        
        # Create a command handler
        on_command = TVCommandCreatedHandler()
        cmd_def.commandCreated.add(on_command)
        handlers.append(on_command)
        
        # Execute the command
        cmd_def.execute()
        
        # Prevent this module from being terminated 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()))


class TVCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
        
    def notify(self, args):
        try:
            global handlers, _selected_line, _number, _err_message
            
            # Get the command that was created.
            cmd = adsk.core.Command.cast(args.command)
            cmd.isExecutedWhenPreEmpted = False
            inputs = cmd.commandInputs
    
            # Add a selector to get a sketch line
            _selected_line = inputs.addSelectionInput(ID + '_selected_line', 'BaseLine', 'Select a sketch line')
            _selected_line.setSelectionLimits(1, 1)
            _selected_line.selectionFilters = ['SketchLines']        

            # Add a text box to get a number (>=3)
            _number = inputs.addStringValueInput(ID + '_number', 'Number', str(MIN_VALUE))

            
            # Add an error message box for feedback
            _err_message = inputs.addTextBoxCommandInput(ID + '_err_message', '', '', 2, True)
            _err_message.isFullWidth = True

            # Add a input validator
            on_validate_inputs = TVCommandValidateInputsHandler()
            cmd.validateInputs.add(on_validate_inputs)
            handlers.append(on_validate_inputs)
            
            # Connect to the command destroyed event.
            on_destroy = TVCommandDestroyHandler()
            cmd.destroy.add(on_destroy)
            handlers.append(on_destroy)
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
            
    
class TVCommandValidateInputsHandler(adsk.core.ValidateInputsEventHandler):
    def __init__(self):
        super().__init__()
        
    def notify(self, args):
        try:
            global _err_message
            event_args = adsk.core.ValidateInputsEventArgs.cast(args)
            
            _err_message.text = ''
 
            if not _number.value.isdigit():
                _err_message.text = 'Number must be a whole number'
                event_args.areInputsValid = False
                return
            else:
                segment_count = int(_number.value)

            if segment_count < 3:
                _err_message.text = 'Number must be 3 or more'
                event_args.areInputsValid = False
                return           
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
        
        
# Event handler that reacts to when the command is destroyed. This terminates the script.            
class TVCommandDestroyHandler(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:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
0 Likes
608 Views
4 Replies
Replies (4)
Message 2 of 5

rory2WEHA
Explorer
Explorer

I'm a few years behind this one but I have the same issue, did you ever resolve it?

0 Likes
Message 3 of 5

j.han97
Advocate
Advocate

Just guessing: Since selection limits are specified Fusion 360 will wait till the selection input is satisfied (in this case 1 selection has been made) before it goes on to validate the inputs.

 

Try disabling the selection limits and see if the issue exists. 

Message 4 of 5

kandennti
Mentor
Mentor

Hi @rory2WEHA .

 

Why not use the InputChanged event to send a message to warn?

https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-1c8998bd-c4b1-4b91-881d-0b57cf468a5f 

 

I modified the above example.

・・・
class TVCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
        
    def notify(self, args):
        try:
            global handlers, _selected_line, _number, _err_message
            
            # Get the command that was created.
            cmd = adsk.core.Command.cast(args.command)
            cmd.isExecutedWhenPreEmpted = False
            inputs = cmd.commandInputs
    
            # Add a selector to get a sketch line
            _selected_line = inputs.addSelectionInput(ID + '_selected_line', 'BaseLine', 'Select a sketch line')
            _selected_line.setSelectionLimits(1, 1)
            _selected_line.selectionFilters = ['SketchLines']        

            # Add a text box to get a number (>=3)
            _number = inputs.addStringValueInput(ID + '_number', 'Number', str(MIN_VALUE))

            
            # Add an error message box for feedback
            _err_message = inputs.addTextBoxCommandInput(ID + '_err_message', '', '', 2, True)
            _err_message.isFullWidth = True

            # Add a input validator
            on_validate_inputs = TVCommandValidateInputsHandler()
            cmd.validateInputs.add(on_validate_inputs)
            handlers.append(on_validate_inputs)
            
            # Connect to the command destroyed event.
            on_destroy = TVCommandDestroyHandler()
            cmd.destroy.add(on_destroy)
            handlers.append(on_destroy)

            # ***addition***
            onInputChanged = MyInputChangedHandler()
            cmd.inputChanged.add(onInputChanged)
            handlers.append(onInputChanged)

        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
・・・
class TVCommandValidateInputsHandler(adsk.core.ValidateInputsEventHandler):
    def __init__(self):
        super().__init__()
        
    def notify(self, args):
        adsk.core.Application.get().log(args.firingEvent.name)
        try:
            global _err_message
            event_args = adsk.core.ValidateInputsEventArgs.cast(args)
 
            if not _number.value.isdigit():
                event_args.areInputsValid = False
                return
            else:
                segment_count = int(_number.value)

            if segment_count < 3:
                event_args.areInputsValid = False
                return           
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
・・・
class MyInputChangedHandler(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.InputChangedEventArgs):
        global _err_message
        _err_message.text = ''

        if not _number.value.isdigit():
            _err_message.text = 'Number must be a whole number'
            return
        else:
            segment_count = int(_number.value)

        if segment_count < 3:
            _err_message.text = 'Number must be 3 or more'
            return     

 

0 Likes
Message 5 of 5

adonno
Enthusiast
Enthusiast

To be honest I don't even remember what piece of code I was working on at the time when I found this. I'm fairly certain that I did not find a solution but the suggestion from kandennti in the thread might be a good solution. I just do not have the time right now to dig back into this but would be interested to know if that suggestion solves your issue.

0 Likes