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: 

Problem with pre-populating multiple selection inputs

7 REPLIES 7
SOLVED
Reply
Message 1 of 8
j.han97
342 Views, 7 Replies

Problem with pre-populating multiple selection inputs

Hi all,

 

I have multiple selection inputs for my addin. They are designed to hold different selection filters (body & face) and must be separated.

 

command = adsk.core.CommandCreatedEventArgs.cast(args).command
            inputs = command.commandInputs
            body_selection = inputs.addSelectionInput('body_selection', 'Select body', 'Click on body to select')
            body_selection.addSelectionFilter('Bodies')
            body_selection.setSelectionLimits(0)
            
            face_selection = inputs.addSelectionInput('face_selection', 'Select face', 'Click on face to select')
            face_selection.addSelectionFilter('Faces')
            face_selection.setSelectionLimits(0)

 

 The selections made by users have to be remembered and re-applied next time when users use this command again. Therefore, I stored the selections in two global lists, and used the activate event of command to pre-populate the selections.

 

global _sel_body, _sel_face
            ipts = adsk.core.CommandEventArgs.cast(args).command.commandInputs
            #Pre-populate body selections if any
            if len(_sel_body) > 0:
                body_selection = ipts.itemById('body_selection')
                for body in _sel_body:
                    body_selection.addSelection(body)
            #Pre-populate face selections if any
            if len(_sel_face) > 0:
                face_selection = ipts.itemById('face_selection')
                for face in _sel_face:
                    face_selection.addSelection(face)

 

To record the selections, I used inputChanged event to detect changes in the selection inputs.

 

global _sel_body, _sel_face
            ipt = adsk.core.InputChangedEventArgs.cast(args).input
            if ipt.id == 'body_selection':
                _sel_body = [ipt.selection(s).entity for s in range(ipt.selectionCount)]
            elif ipt.id == 'face_selection':
                _sel_face = [ipt.selection(s).entity for s in range(ipt.selectionCount)]

 

 

However, when I tested my code, it did not work as expected (in the pre-populating step, to be precise). First I selected a body and a face for the two selection inputs respectively. Note that the selected face did not belong to the selected body.

jhan97_0-1637890546814.png

After clicking OK, I opened the command again, expecting the same selection (1 body, 1 face) would be made. But instead, 2 bodies & 1 face were selected.

jhan97_1-1637890705850.png

The body of the selected face was selected, although I never selected it. For my understanding, it is because the pre-populating action triggers the inputChanged event.

 

How can I avoid this behavior? If anyone wants to reproduce this situation, I have attached the addin & the test model in a zip file. Many thanks!

 

 

Labels (3)
7 REPLIES 7
Message 2 of 8
tykapl.breuil
in reply to: j.han97

If I understood correcly, you need to remember with what selections the last commands were executed with right ? In that case, why not put the 'memory' step in the command execute handler rather than the input changed handler ?

Message 3 of 8
kandennti
in reply to: j.han97

Hi @j.han97 .

 

I was able to reproduce the phenomenon.

I tried de-focusing the body_selection and reselecting the face_selection first, but the result was the same.

It seems to be a bug, but I'm not sure if the cause is the SelectionCommandInput or the activate event.

Message 4 of 8
j.han97
in reply to: j.han97

Hi all,

 

I am guessing that the command input is focusing on the first selection input, therefore in the pre-population step, the selected faces are added to the body_selection (which is the first selection input). To verify this, I used only activate & execute handler to store & pre-populate the selections.

class selections_activateHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    
    def notify(self, args):
        try:
            global _sel_body, _sel_face
            ipts = adsk.core.CommandEventArgs.cast(args).command.commandInputs
            _app.log('\tPrepopulate started')
            if len(_sel_body) > 0:
                body_selection = ipts.itemById('body_selection')
                for body in _sel_body:
                    body_selection.addSelection(body)
            
            if len(_sel_face) > 0:
                face_selection = ipts.itemById('face_selection')
                for face in _sel_face:
                    face_selection.addSelection(face)
                    
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class selections_executeHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    
    def notify(self, args):
        try:
            global _sel_body, _sel_face
            _sel_body = []; _sel_face = []
            
            command = adsk.core.CommandEventArgs.cast(args).command
            inputs = command.commandInputs
            body_selection = inputs.itemById('body_selection')
            for i in range(body_selection.selectionCount):
                _sel_body.append(body_selection.selection(i).entity)
            face_selection = inputs.itemById('face_selection')
            for i in range(face_selection.selectionCount):
                _sel_face.append(face_selection.selection(i).entity)
            
            _ui.messageBox(f'{len(_sel_body)} bodies, {len(_sel_face)} faces')
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 The situation remained the same. Now it seems that the the problem comes from either the activate handler or the selectionCommandInput as suggested by @kandennti .

Until this step I am completely confused because this pre-population method is suggested in the API reference manual (If you want to pre-populate the selection when the command is starting, you can use this method in the activate method of the Command). I am hoping someone from the development team can provide some guidance or confirm that this is a bug (so it won't trouble me anymore!).

 

To @tykapl.breuil , the real code is slightly more complex than this sample script: I wanted to 'extend' the selection from user, for example, include similar bodies (in terms of volume, mass, etc) when a body is selected. Therefore I had to monitor the new selection and do the calculations in the inputChanged handler. I didn't realize that this is actually kind of stupid here (:D).

 

Thank you all for your comments!

Message 5 of 8
j.han97
in reply to: j.han97

Small update: I thought I found the solution by setting the focus to face_selection before adding selections to it:

 

class selections_activateHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    
    def notify(self, args):
        try:
            global _sel_body, _sel_face
            ipts = adsk.core.CommandEventArgs.cast(args).command.commandInputs
            _app.log('\tPrepopulate started')
            if len(_sel_body) > 0:
                body_selection = ipts.itemById('body_selection')
                for body in _sel_body:
                    body_selection.addSelection(body)
            
            
            if len(_sel_face) > 0:  
                face_selection = ipts.itemById('face_selection') 
                #Set focus to face_selection
                face_selection.hasFocus = True
                for face in _sel_face:
                    face_selection.addSelection(face)
            
                    
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

But it still failed. 

Message 6 of 8
kandennti
in reply to: j.han97

@j.han97 .

 

If it's just "face_selection", it works correctly.

 

It is true that if there are multiple SelectionCommandInputs, setSelectionLimits will not work correctly and the OK button will function even though the condition is not met.

It's possible that SelectionCommandInput is not designed to be used more than once.

Message 7 of 8
j.han97
in reply to: kandennti

Hi @kandennti ,

 

I see. But since it is not practical for me to mix up the selection inputs, I guess I will have to create separate buttons for users for different selection types.

 

Thank you.

Message 8 of 8
tykapl.breuil
in reply to: j.han97

This addin only adds a face to the face selection input and still displays the bug :

#Author-Juan
#Description-Testing for addins

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

class selections_commandCreatedEventHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    
    def notify(self, args):
        try:
            product = _app.activeProduct
            design = adsk.fusion.Design.cast(product)
            rootComp = design.rootComponent
            command = adsk.core.CommandCreatedEventArgs.cast(args).command
            inputs = command.commandInputs
            body_selection = inputs.addSelectionInput('body_selection', 'Select body', 'Click on body to select')
            body_selection.addSelectionFilter('Bodies')
            body_selection.setSelectionLimits(0)
            
            face_selection = inputs.addSelectionInput('face_selection', 'Select face', 'Click on face to select')
            face_selection.addSelectionFilter('Faces')
            face_selection.setSelectionLimits(0)

            face_selection = inputs.itemById('face_selection')
            face_selection.hasFocus = True
            face_selection.addSelection(rootComp.bRepBodies.item(0).faces.item(0))

        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


_app = adsk.core.Application.get()
_ui  = _app.userInterface
_handlers = []


def run(context):
    try:
        
        #Get command definitions & design workspace
        cmd_def = _ui.commandDefinitions
        des_wp = _ui.workspaces.itemById('FusionSolidEnvironment')
        product = _app.activeProduct
        design = adsk.fusion.Design.cast(product)

        #Get tools tab
        tools_tab = des_wp.toolbarTabs.itemById('ToolsTab')
        
        #Get add-in panel
        addin_panel = tools_tab.toolbarPanels.itemById('SolidScriptsAddinsPanel')
            
        
        #Add selections command definition
        selections_cmdDef = cmd_def.itemById('selections_cmd')
        if not selections_cmdDef:
            selections_cmdDef = cmd_def.addButtonDefinition('selections_cmd', 'Multiple selections', 'Sample addin to test multiple selections', './resources/selections')
        
        #Add to panel
        selections_ctrl = addin_panel.controls.itemById('selections_cmd')
        if not selections_ctrl:
            selections_ctrl = addin_panel.controls.addCommand(selections_cmdDef)
        
        #Set visibility of button
        selections_ctrl.isVisible = True; selections_ctrl.isPromoted = True; selections_ctrl.isPromotedByDefault = True
        
        #Connect to commandCreatedEvent
        selections_commandCreated = selections_commandCreatedEventHandler()
        selections_cmdDef.commandCreated.add(selections_commandCreated)
        _handlers.append(selections_commandCreated)
        
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

def stop(context):
    try:
        pass
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

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