DropDownCommandInput property change notification fires twice when isSelected changed

DropDownCommandInput property change notification fires twice when isSelected changed

tim.collins29V9X
Enthusiast Enthusiast
338 Views
2 Replies
Message 1 of 3

DropDownCommandInput property change notification fires twice when isSelected changed

tim.collins29V9X
Enthusiast
Enthusiast

I'm using a  DropDownCommandInput to simulate a "File:" menu with items for New, Close, Open, Save, Save As etc When "Open" is selected the NotifyInputChanged function shows that the "value" of the DropDownCommandInput has changed to "Open" and this is processed fine.

However it is confusing to always see the previously-used command, such as "Open" showing. I made a dummy list item "File:" as the first element and after processing "Open" I do this:

 

 

 

 

            self.fileDropDown.listItems.item(0).isSelected = True

 

 

 
Awesome. I always see "File:" at the top and it sort of looks like a menu.

I have two issues or possible bugs.

1. I never get a NotifyInputChanged on the first element 0 named "File:" Worrysome.

2. I get two NotifyInputChanged calls. First when selected and again when I set "0" to isSelected = True 
 
Two calls to Open are very bad. When I remove the code that selects element "0" then both those bugs go away but it no longer looks like a menu.

Is there a way to change the selection of a drop down list inside the change notification code path that doesn't cause losing one event and getting a double of another?  This feels like a threading issue as I'm doing an action that will cause one item to de-select (and fire an un-wanted change event) and the other event (0 is selelected) to be eaten by a grue.
0 Likes
Accepted solutions (1)
339 Views
2 Replies
Replies (2)
Message 2 of 3

Jorge_Jaramillo
Collaborator
Collaborator
Accepted solution

Hi @tim.collins29V9X ,

 

The InputChanged event is being fired twice, one for the user selection and the second when you set it back to 'File', which is the normal behavior of the application.

What is not correct is when you get twice the same value the user selected. And this is that way because the second InputChanged event is being fired while the first one is not completed yet.

To solve this, you can fire a custom event instead of changing the value of the DropDownCommandInput, then in the custom event you can set the value to the DropDownCommand you want.

 

From the Application.fireCustomEvent Method documentation: "Firing a custom event does not immediately result in the event handler being called. When a custom event is fired the event is put on the queue and will be handled in the main thread when Fusion 360 is idle."

 

You have to make the following changes in your source code:

 

#1) add to global variables
myCustomEvent     = 'customEvent'
customEvent       = None

#2) define the custom event handler where you set the 'File' option as selected:
class customEventHandler(adsk.core.CustomEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            fileDrpDwn.listItems.item(0).isSelected = True
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

#3) Register the custom event in command input setup inside the run() function, before the cmdDef.execute() statement:
        global customEvent
        customEvent = _app.registerCustomEvent(myCustomEvent)
        onThreadEvent = customEventHandler()
        customEvent.add(onThreadEvent)
        _handlers.append(onThreadEvent)

#4) Add this inside notify function in CommandDestroyHandler, to unregister the custom event, otherwise you'll get an error next time you execute your script because the event was registered before:
            _app.unregisterCustomEvent(myCustomEvent)

#5) Fire the event inside ChangeInpuntHandler, instead of self.fileDropDown.listItems.item(0).isSelect = True statement; i'm checking here it's has other value than 'File' to avoid a infite loop maybe:
                fileItem = adsk.core.ListItem.cast(fileDrpDwn.selectedItem)
                if fileItem and fileItem.name != 'File':
                    _app.fireCustomEvent(myCustomEvent)

 

 

Hope this help.  Let me know your results.

 

Regards,

Jorge

 

 

Message 3 of 3

tim.collins29V9X
Enthusiast
Enthusiast

Thank you, that solved the problem. It worked for me with only minimal debugging time. It does make sense. I've had to do more or less the same thing in X Windows, MS Windows, Mac, etc etc etc.

class CustomEventHandler(CustomEventHandler):
    
    _handlers = []

    def __init__(self, fileDropDown: DropDownCommandInput):
        super().__init__()
        self.fileDropDown = fileDropDown
        self.app = Application.get()
        self.ui = self.app.userInterface

    def notify(self, args):
        try:
            self.fileDropDown.listItems.item(0).isSelected = True
        except:
            if self.ui:
                self.ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))



I did have to work around some issues with imports of not fully initialized code (_handlers) but not a big deal.