How to bind "Stroke Style" to a boolean property

I’m in the beginning stages of a project and am currently building motor templates. Each template has the following custom properties:
running_color (color)
stopped_color (color)
alarm_color (color)
running_indication (Boolean)
alarm_indication (Boolean)

I would like to know how I could use the Boolean “alarm_indication” to cause the motor’s “Stroke style” to increase to a width of 5.

As far as I can see this is not possible with binding - you’ll have to use Python to do this. The information about setting stroke style in code came from tebright1’s post here.

  1. Right click on the background of your motor template and select ‘Scripting’
  2. Select the propertyChange / propertyChange event
  3. Enter the following code:

if event.propertyName == 'alarm_indication': from java.awt import BasicStroke rectangle = event.source.getComponent('Rectangle') if event.newValue == 1: rectangle.strokeStyle = BasicStroke(5) else: rectangle.strokeStyle = BasicStroke(1)
You will obviously have to change what object you are getting a reference for. Mine is called ‘Rectangle’. Your motor might consist of a number of shapes - you’ll have to set the strokeStyle for all the ones you want to increase in width.

This is why I created the objectScript() expression function in the Simulation Aids module – I wanted to efficiently use jython within bindings.

What would the given example look like using objectScript() Phil?

[quote=“AlThePal”]What would the given example look like using objectScript() Phil?[/quote]First, you’d create a project or shared script that converts a boolean to a stroke:from java.awt import BasicStroke def alarmStroke(thick): return BasicStroke(5) if thick else BasicStroke(1)Then call it from the binding expression with the boolean as an extra argument:objectScript('project.stroke.alarmStroke(args[0])', {Root Container.alarm_indication})Note that arguments after the string of code are presented as a tuple named ‘args’.
The other major advantage of this approach is it always runs – no need to switch the designer to preview mode.

Note that in Ignition 7.8 you can pass arguments directly to runScript:

runScript('project.stroke.alarmStroke', 0, {Root Container.alarm_indication})

(You still have to specify the polling rate, but if you set it to 0 that’s the same as no polling)

Take a look at this thread for other ideas, as well. Files have been refreshed, so all the downloadable content will work.

Unfortunately, runScript() can only pass arguments when the expression string is a function name. I often want to use one-liners for extra functionality. Say one rectangle needs a different alarm thickness – with objectScript, you can put that customization right in the expression:objectScript('project.stroke.BasicStroke(10) if args[0] else project.stroke.BasicStroke(1)', {Root Container.alarm_indication})Note that java.awt.BasicStroke was imported into project.stroke, so it’s available to Ignition scripts with no further import.

Just for completeness, here’s how you do this with runScript and Custom Methods on templates:

  1. Create a template e.g. Test
  2. Create an alarm_indication Template Parameter on the template
  3. Put a custom method on the root of the template:

def setBorderStyle(self, alarm_indication): from java.awt import BasicStroke return BasicStroke(5) if alarm_indication else BasicStroke(1) 4. Put the following expression on the Stroke Style of the object you wish to animate:

runScript('self.parent.setBorderStyle(' + {Test.alarm_indication} + ')', 0)

Note the path to access the template root’s custom method from the object. Putting the custom method on the object itself and using a path of self.setBorderStyle works with objects on windows but not with templates.

As Phil points out in the following discussion, this form of the code is faster: runScript('self.parent.setBorderStyle', 0, {Test.alarm_indication})

[quote=“AlThePal”]runScript('self.parent.setBorderStyle(' + {Test.alarm_indication} + ')', 0)[/quote]You can do this, but it won’t scale. Changing the executable string that runScript uses (or objectScript) will increase the execution time by a couple orders of magnitude. I’ve seen tens of milliseconds vs. hundreds of microseconds in typical cases. Don’t make jython compile things on the fly. That’s why argument passing is so important.

How can you tell how long this is taking?

[quote=“AlThePal”]How can you tell how long this is taking?[/quote]I instrumented objectScript() and view() while I developed them. Getting rid of jython compiler overhead wasn’t the original motivator for these functions, but that objective was quickly added. Oh, and the instrumentation is still present in the view() function and can be displayed by setting its logger to DEBUG mode.

I can understand that you might have instrumented your own code, but how can you tell how long an internal Ignition function like runScript is taking?

You can nest it inside of a do-nothing expression function that you have instrumented.