Does every CommandCreated require a unique CommandCreatedEventHandler?

Does every CommandCreated require a unique CommandCreatedEventHandler?

Anonymous
646 Views
3 Replies
Message 1 of 4

Does every CommandCreated require a unique CommandCreatedEventHandler?

Anonymous
Not applicable

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!

0 Likes
Accepted solutions (2)
647 Views
3 Replies
Replies (3)
Message 2 of 4

ekinsb
Alumni
Alumni
Accepted solution

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
Autodesk
Autodesk
Accepted solution

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

Anonymous
Not applicable

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

0 Likes