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: 

Does every CommandCreated require a unique CommandCreatedEventHandler?

3 REPLIES 3
SOLVED
Reply
Message 1 of 4
k.mc
435 Views, 3 Replies

Does every CommandCreated require a unique CommandCreatedEventHandler?

Apologies in advance - I have very limited programming experience. I am open to any other ways my code can be improved.

 

I have a functioning add-in that gives me several buttons (20+) and each button performs a different variation of a single function. Rather than write code for each button individually, create them with a loop. My problem is that all of the buttons will do the same thing unless I create a unique handler for each button. I have included a simplified version of my code below; only creates two buttons and the function is a UI message box.

 

 

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

app = adsk.core.Application.get()
ui  = app.userInterface
handlers = []

# dictionaries
msg0 =  {'id':'msg0', 'name':'m0', 'tooltip':'', 'resources':'Resources/aaa', 'text':'123'}
msg1 = {'id':'msg1', 'name':'m1', 'tooltip':'', 'resources':'Resources/aaa', 'text':'456'}

messages = [msg0, msg1]

selMsg = None

class eventHandler0(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        global selMsg        
        selMsg = messages[0]        
        popMsg()

class eventHandler1(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        global selMsg
        selMsg = messages[1]        
        popMsg()

events = [eventHandler0(), eventHandler1()]

# Send message           
def popMsg(): 
    
    try:
        ui.messageBox(selMsg['text'])
        
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
            

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        cmdDefs = ui.commandDefinitions
        targetPanel = ui.allToolbarPanels.itemById('SolidCreatePanel')   
        global selMsg        
        
        # Create Panel for Buttons
        msgPanel = targetPanel.controls.addDropDown('message', 'Resources/aaa', 'mPanel')        
        
        i = 0
        # For each view
        while i < 2:
            selMsg = messages[i]
            
            # Create button
            customMsg = cmdDefs.addButtonDefinition(selMsg['id'], selMsg['name'], selMsg['tooltip'], selMsg['resources'])
                
            # Connect command to button
            eventCreated = events[i]
            customMsg.commandCreated.add(eventCreated)
            handlers.append(eventCreated)
            
            # Add button to panel        
            msgPanel.controls.addCommand(customMsg)
            
            i = i + 1

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

def stop(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        cmdDefs = ui.commandDefinitions
        targetPanel = ui.allToolbarPanels.itemById('SolidCreatePanel') 
        global selMsg        
        
        i = 0
        # For each view
        while i < 2:
            selMsg = messages[i]         
            
            # Delete button
            msgPanel = targetPanel.controls.itemById('mPanel')
            if msgPanel:
                kControl = msgPanel.controls.itemById(selMsg['id'])
                if kControl:
                    kControl.deleteMe()
                    
            # Delete command
            customMsg = cmdDefs.itemById(selMsg['id'])        
            if customMsg:
                customMsg.deleteMe()
            
            i = i + 1
    
        # Delete drop down panel
        msgPanel.deleteMe()
    
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

I know why all the buttons do the same thing with a single eventHandler: selMsg is set by the last button created and never changes. Multiple eventHandlers that change selMsg is the workaround, but I was hoping for a more elegant solution.

 

Ideally, I would like a single eventHandler class with some code that determines which button has been clicked. I am imagining something like this:

 

class eventHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        global selMsg
x = None if button0 is clicked:
x = 0
if button1 is clicked:
x = 1 selMsg = messages[x] popMsg()

I cannot seem to wrap my head around how eventHandler.notify is called. What information is being sent when a user clicks a button in the UI? Can I add another argument to eventHandler that is retained in the handlers list? Is there a way to make decisions based on the button that is clicked?


Thanks for the help!

3 REPLIES 3
Message 2 of 4
ekinsb
in reply to: k.mc

You can use the same handler for multiple command definitions.  I modified your sample to do this by changing this:

 

            # Connect command to button
            eventCreated = events[i]
            customMsg.commandCreated.add(eventCreated)
            handlers.append(eventCreated)

to this:

            # Connect command to button
            eventCreated = events[0]
            customMsg.commandCreated.add(eventCreated)
            handlers.append(eventCreated)

And the eventHandler0 class to this:

class eventHandler0(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        cmdCreatedArgs = adsk.core.CommandCreatedEventArgs.cast(args)
        cmd = cmdCreatedArgs.command        
        app = adsk.core.Application.get()
        ui = app.userInterface
        ui.messageBox('Event handler is firing for: ' + cmd.parentCommandDefinition.id)

Notice that the event provides a CommandCreatedEventArgs object from which you can get the command that the event is firing for.


Brian Ekins
Inventor and Fusion 360 API Expert
Mod the Machine blog
Message 3 of 4
KrisKaplan
in reply to: ekinsb

Also, don't forget that the handler is a class like any other.  Instances of a class can have instance specific state held in data members.  So just set any instance specific state on the handler when you create it (either as constructor arguments, or set on the instance after creation).  For example, you could change your handler __init__ function to something like the following.

 

events = [eventHandler(0), eventHandler(1)]

class eventHandler(adsk.core.CommandCreatedEventHandler):
def __init__(self, x):
super().__init__()
self.x = x
def notify(self, args):
...
msg = messages[self.x];

Any input specific state, should be held by the appropriate handler instance, or by a class structure that models the command and inputs and contains these handlers.

 

Kris

 



Kris Kaplan
Message 4 of 4
k.mc
in reply to: k.mc

Awesome! Thank you both @ekinsb and @KrisKaplan. Both implementations did exactly what I needed.

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