Palette to get data from python keeps looping

Palette to get data from python keeps looping

info83PHN
Advocate Advocate
972 Views
4 Replies
Message 1 of 5

Palette to get data from python keeps looping

info83PHN
Advocate
Advocate

Trying to modified the palette / python code to :

1. Click the palette html button to activate the python script

2. python script to get some data from the Components

3. python feed the data back to the palette

4. palette to display the returned message.

added bonus would be to have the palette window display when the add-on is run.

 

Problem - palette displays, but when clicking on the button, it loops with the number returned from python updating all the time.

 

I stripped out the code for the "Send Info to HTML" add-on dropdown menu, as I want the python script to return the required info once the palette html button is clicked.

 

The palette code is :

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <p>Click the button below to send data to Fusion.</p>
        <button type='button' onclick='sendInfoToFusion()'>Click to send info to Fusion</button> 
        <p id='p1'>Ready to run.</p>
        <br /><br />
	
    </body>
    <script>
        function sendInfoToFusion(){

			// arg1 = 'ReadVolumes' will tell the python script which data I want returned to display on the palette.

            var args = {
                arg1 : "ReadVolumes",
            };
            adsk.fusionSendData('send', JSON.stringify(args));
        }
        
        window.fusionJavaScriptHandler = {handle: function(action, data){
            try {
                if (action == 'send') {
					document.getElementById('p1').innerHTML = data;
				}
				else if (action == 'debugger') {
                    debugger;
				}
				else {
					return 'Unexpected command type: ' + action;
                }
            } catch (e) {
                console.log(e);
                console.log('exception caught with command: ' + action + ', data: ' + data);
            }
            return 'OK';
        }};
    </script>
</html>

 

The python code is :

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

# global set of event handlers to keep them referenced for the duration of the command
handlers = []
_app = adsk.core.Application.cast(None)
_ui = adsk.core.UserInterface.cast(None)
num = 0


# Event handler for the commandExecuted event - show palette, create handlers

class ShowPaletteCommandExecuteHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            # Create and display the palette.
            palette = _ui.palettes.itemById('myPalette')
            if not palette:
                palette = _ui.palettes.add('myPalette', 'My Palette', 'palette.html', True, True, True, 300, 200)

                # Dock the palette to the right side of Fusion window.
                palette.dockingState = adsk.core.PaletteDockingStates.PaletteDockStateRight
    
                # Add handler to HTMLEvent of the palette.
                onHTMLEvent = MyHTMLEventHandler()
                palette.incomingFromHTML.add(onHTMLEvent)   
                handlers.append(onHTMLEvent)
    
                # Add handler to CloseEvent of the palette.
                onClosed = MyCloseEventHandler()
                palette.closed.add(onClosed)
                handlers.append(onClosed)   
            else:
                palette.isVisible = True                               
        except:
            _ui.messageBox('Command executed failed: {}'.format(traceback.format_exc()))


# Event handler for the commandCreated event.
class ShowPaletteCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()              
    def notify(self, args):
        try:
            command = args.command
            onExecute = ShowPaletteCommandExecuteHandler()
            command.execute.add(onExecute)
            handlers.append(onExecute)                                     
        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))     


# Event handler for the commandExecuted event.
class SendInfoCommandExecuteHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            # Send information to the palette. This will trigger an event in the javascript
            # within the html so that it can be handled.
            palette = _ui.palettes.itemById('myPalette')
            if palette:
                global num
                num += 1
                palette.sendInfoToHTML('send', 'Message has been sent ' + str(num) + ' times')                        
        except:
            _ui.messageBox('Command executed failed: {}'.format(traceback.format_exc()))


# Event handler for the commandCreated event.
class SendInfoCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()              
    def notify(self, args):
        try:
            command = args.command
            onExecute = SendInfoCommandExecuteHandler()
            command.execute.add(onExecute)
            handlers.append(onExecute)                                     
        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))     


# Event handler for the palette close event.
class MyCloseEventHandler(adsk.core.UserInterfaceGeneralEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            _ui.messageBox('Close button is clicked.') 
        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


# Event handler for the palette HTML event.                
class MyHTMLEventHandler(adsk.core.HTMLEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            global num
            num += 1
            palette = _ui.palettes.itemById('myPalette')
            palette.sendInfoToHTML('send', 'It has been sent ' + str(num) + ' times')

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

                
def run(context):
    try:
        global _ui, _app
        _app = adsk.core.Application.get()
        _ui  = _app.userInterface
        
        # Add a command that displays the panel.
        showPaletteCmdDef = _ui.commandDefinitions.itemById('showPalette')
        if not showPaletteCmdDef:
            showPaletteCmdDef = _ui.commandDefinitions.addButtonDefinition('showPalette', 'Show Custom Palette', 'Show the custom palette', '')
            # Connect to Command Created event.
            onCommandCreated = ShowPaletteCommandCreatedHandler()
            showPaletteCmdDef.commandCreated.add(onCommandCreated)
            handlers.append(onCommandCreated)
        
        panel = _ui.allToolbarPanels.itemById('SolidScriptsAddinsPanel')
        cntrl = panel.controls.itemById('showPalette')
        if not cntrl:
            panel.controls.addCommand(showPaletteCmdDef)
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


def stop(context):
    try:        
        # Delete the palette created by this add-in.
        palette = _ui.palettes.itemById('myPalette')
        if palette:
            palette.deleteMe()
        # Delete controls and associated command definitions created by this add-ins
        panel = _ui.allToolbarPanels.itemById('SolidScriptsAddinsPanel')
        cmd = panel.controls.itemById('showPalette')
        if cmd:
            cmd.deleteMe()
        cmdDef = _ui.commandDefinitions.itemById('showPalette')
        if cmdDef:
            cmdDef.deleteMe() 
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

0 Likes
Accepted solutions (2)
973 Views
4 Replies
Replies (4)
Message 2 of 5

j4n.vokurka
Advocate
Advocate
Accepted solution

That occurs because you are perpetually calling the sendInfoToHTML method. 

Short explanation: button is pressed in palette => 
incomingFromHTML is triggerred => sendInfoToHTML() is used in handler => incomingFromHTML is triggerred again - cycle is born.

To tackle this you have to check the json data you receive from the palette and determine what has happened and if you want to react to that or not.

I have adjusted the python and javascript code because there are a lot of handlers I think you don't need right now. The logic you need starts on line 63.

palette:

 

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <p>Click the button below to send data to Fusion.</p>
        <button type='button' onclick='sendInfoToFusion()'>Click to send info to Fusion</button> 
        <p id='p1'>Ready to run.</p>
        <br /><br />
	
    </body>
    <script>
        function sendInfoToFusion(){

			// arg1 = 'ReadVolumes' will tell the python script which data I want returned to display on the palette.

            var args = {
                data : "ButtonPressed",
            };
            adsk.fusionSendData('send', JSON.stringify(args));
        }
        
        window.fusionJavaScriptHandler = {handle: function(action, data){
            try {
                if (action == 'send') {
					document.getElementById('p1').innerHTML = data;
				}
				else if (action == 'debugger') {
                    debugger;
				}
				else {
					return 'Unexpected command type: ' + action;
                }
            } catch (e) {
                console.log(e);
                console.log('exception caught with command: ' + action + ', data: ' + data);
            }
            return 'OK';
        }};
    </script>
</html>

 


python:

 

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

# global set of event handlers to keep them referenced for the duration of the command
handlers = []
_app = adsk.core.Application.cast(None)
_ui = adsk.core.UserInterface.cast(None)
num = 0


# Event handler for the commandCreated event.
class ShowPaletteCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()              
    def notify(self, args):
        try:
            command = args.command
            onExecute = ShowPaletteCommandExecuteHandler()
            command.execute.add(onExecute)
            handlers.append(onExecute)                                     
        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))     


# Event handler for the commandExecuted event - show palette, create handlers
class ShowPaletteCommandExecuteHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            # Create and display the palette.
            palette = _ui.palettes.itemById('myPalette')
            if not palette:
                palette = _ui.palettes.add('myPalette', 'My Palette', 'palette.html', True, True, True, 300, 200)

                # Dock the palette to the right side of Fusion window.
                palette.dockingState = adsk.core.PaletteDockingStates.PaletteDockStateRight
    
                # Add handler to HTMLEvent of the palette.
                onHTMLEvent = MyHTMLEventHandler()
                palette.incomingFromHTML.add(onHTMLEvent)   
                handlers.append(onHTMLEvent)
    
                # Add handler to CloseEvent of the palette.
                onClosed = MyCloseEventHandler()
                palette.closed.add(onClosed)
                handlers.append(onClosed)   
            else:
                palette.isVisible = True                               
        except:
            _ui.messageBox('Command executed failed: {}'.format(traceback.format_exc()))



# Event handler for the palette HTML event.                
class MyHTMLEventHandler(adsk.core.HTMLEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            global num            

            htmlArgs = adsk.core.HTMLEventArgs.cast(args)
            data = json.loads(htmlArgs.data)   
             
            if (data['data'] == "ButtonPressed"):
                num += 1  # call your script here and retreive needed component info
                palette = _ui.palettes.itemById('myPalette')
                palette.sendInfoToHTML('send', 'It has been sent ' + str(num) + ' times')          
            elif (data['data'] == "OK"): 
                return      
            else:
                # some error
                return            

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

# Event handler for the palette close event.
class MyCloseEventHandler(adsk.core.UserInterfaceGeneralEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            _ui.messageBox('Close button is clicked.') 
        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
    
def run(context):
    try:
        global _ui, _app
        _app = adsk.core.Application.get()
        _ui  = _app.userInterface
        
        # Add a command that displays the panel.
        showPaletteCmdDef = _ui.commandDefinitions.itemById('showPalette')
        if not showPaletteCmdDef:
            showPaletteCmdDef = _ui.commandDefinitions.addButtonDefinition('showPalette', 'Show Custom Palette', 'Show the custom palette', '')

            # Connect to Command Created event.
            onCommandCreated = ShowPaletteCommandCreatedHandler()
            showPaletteCmdDef.commandCreated.add(onCommandCreated)
            handlers.append(onCommandCreated)
        
        panel = _ui.allToolbarPanels.itemById('SolidScriptsAddinsPanel')
        cntrl = panel.controls.itemById('showPalette')
        if not cntrl:
            panel.controls.addCommand(showPaletteCmdDef)
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


def stop(context):
    try:        
        # Delete the palette created by this add-in.
        palette = _ui.palettes.itemById('myPalette')
        if palette:
            palette.deleteMe()

        # Delete controls and associated command definitions created by this add-ins
        panel = _ui.allToolbarPanels.itemById('SolidScriptsAddinsPanel')
        cmd = panel.controls.itemById('showPalette')
        if cmd:
            cmd.deleteMe()
        cmdDef = _ui.commandDefinitions.itemById('showPalette')
        if cmdDef:
            cmdDef.deleteMe() 
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

 

 

 

 

 


 

Message 3 of 5

info83PHN
Advocate
Advocate

@j4n.vokurka my sincere Thanks. I just could not understand why it was looping. Your solution worked perfectly. Thank You

0 Likes
Message 4 of 5

j4n.vokurka
Advocate
Advocate
Accepted solution

@info83PHN no problem 🙂

Also if you want to display the palette right away when the add-in is started, you can execute its command definition which will simulate user clicking the button.

Add this at the end of your run method:

showPaletteCmdDef.execute() 



Message 5 of 5

info83PHN
Advocate
Advocate

 PERFECT - Thank You - I was going to make another post for that as I could not find that solution either.

0 Likes