Finding GUI with the same property value

Suppose we have GUI component A1 and A2 which are derived from the same Custom Template A. Now, suppose Template A has Template Property called Prop1.

When put both component A1 and component A2 in the same Root Container in a Window, is there any way we can do in the scripting of, let say, A1 event, to find A2 component - provided that they are the only components in the GUI which has the same Prop1 values?

The similarities between A1 and A2 are not their name - for they may have arbitrarily different names. But we know that A1 and A2 both have the same Prop1 values. Can we find the component by scripting?

Containers have a .getComponents() method that will return a list of the java components inside them. You can iterate through this list testing for your criteria. Youā€™ll probably want to check component classes, then attribute values. The possibilities are endless.

That sounds great! OK, will try to look at that more. Do you happen to have any reference for me to figure out more about the methods, properties, etc which I can use? Is it in the Ignition website (I probably miss it if it does)?

@pturmel: In the end, I follow your and @JGJohnsonā€™s suggestion in the other post and use Template Repeater instead of Container.

Just want to ask if the Template Repeater also has getComponents() to find the list of items under it or the list of items have to be accessed differently (such as using index in ArrayList or key in HashTable?) ā€“ I am not too familiar with Java.

If it is not too difficult for you, I would also like for a minimum example on how can I get the components by checking the property ā€“ as I donā€™t have any idea how to write code in Java style (assuming that this can be done) in the Ignition script (since, AFAIK, the script is supposed to be written in Jython, which is also new for me)

Thanks a lot in advance!

[quote=ā€œianā€]Just want to ask if the Template Repeater also has getComponents() to find the list of items under it or the list of items have to be accessed differently (such as using index in ArrayList or key in HashTable?)[/quote]I briefly looked at this once ā€“ thereā€™s more than one level of nesting, but getComponents() at each level will expose everything.[quote=ā€œianā€]I am not too familiar with Java.[/quote]You donā€™t have to be familiar with writing Java, but you will have to get familiar with Java Swing objects to really apply these techniques. All of Ignitionā€™s components are subclasses of JComponent, and therefore have its methods and properties.[quote=ā€œianā€]If it is not too difficult for you, I would also like for a minimum example on how can I get the components by checking the property[/quote]Something like this on a buttonā€™s actionPerformed event:from com.inductiveautomation.factorypmi.application.components.template import TemplateHolder root = event.source.parent for comp in root.components: print comp.name, comp.class if TemplateHolder.isInstance(comp): print " %s" % comp.templatePath if comp.name.startswith('signal'): print " One of my signals!"A few further notes:[ol][li]In jython, java getter and setter methods that follow NetBeans naming conventions are turned into properties. So .getComponents() can be written .components instead. And such a property will be assignable (writable) if the matching java set*(newValue) method exists.[/li][li]Java objects have a .getClass() method that you can use to obtain the information you need to import component types. (Should be obvious if you run this script.)[/li][li]When you hover over a property in the property pane of Ignitionā€™s designer, it will show you the jython name of that property for that component.[/li][li]Containers and groups will show up in your list. You will need a nested loop to find the components inside them.[/li][li]When you are feeling good about the above, the next step is java reflection.[/li][/ol]

1 Like

Thanks for your help! I currently can progress up to the stage where I can detect the root container component, listing the components and found the component which has the property matches.

However, as I want to get the sub-component of the component with matching property, I encounter another error:

This happen when I try to use the ā€œcompā€ of the ā€œroot.componentsā€ with ā€œgetComponent(ā€˜my signal nameā€™)ā€ method. Usually, we do that to get child component in Ignition. But somehow I got this error when I use the Java wrapper?

[quote]TypeError: getComponent(): 1st arg canā€™t be coerced to int

at org.python.core.Py.TypeError(Py.java:235)
at org.python.core.PyReflectedFunction.throwError(PyReflectedFunction.java:209)
at org.python.core.PyReflectedFunction.throwBadArgError(PyReflectedFunction.java:312)
at org.python.core.PyReflectedFunction.throwError(PyReflectedFunction.java:321)
at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:167)
at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:204)
at org.python.core.PyObject.__call__(PyObject.java:404)
at org.python.core.PyObject.__call__(PyObject.java:408)
at org.python.core.PyMethod.__call__(PyMethod.java:124)
at org.python.pycode._pyx256.f$0(<event:mouseEntered>:55)
at org.python.pycode._pyx256.call_function(<event:mouseEntered>)
at org.python.core.PyTableCode.call(PyTableCode.java:165)
at org.python.core.PyCode.call(PyCode.java:18)
at org.python.core.Py.runCode(Py.java:1275)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:623)
at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.runActions(ActionAdapter.java:168)
at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.invoke(ActionAdapter.java:265)
at 

[/quote]

In the end, I use another for loop and if comp.name == ā€˜my signal componentā€™ to make it work. Nevertheless, I have a custom property called IsSelected in my component.

When we use ā€œnormalā€ Ignition script, we could get and assign the property straightforwardly

myComponent.IsSelected = True

But when I try to do that in my component:

comp.IsSelected = True

it generates error, saying that there is no [i]Attribute/i called IsSelected:

[quote]AttributeError: ā€˜com.inductiveautomation.vision.api.client.componenā€™ object has no attribute ā€˜IsSelectedā€™

at org.python.core.Py.AttributeError(Py.java:173)
at org.python.core.PyObject.noAttributeError(PyObject.java:930)
at org.python.core.PyObject.object___setattr__(PyObject.java:3761)
at org.python.core.PyObject.object___setattr__(PyObject.java:3732)
at org.python.core.PyObject$object___setattr___exposer.__call__(Unknown Source)
at org.python.core.PyObjectDerived.__setattr__(PyObjectDerived.java:990)
at org.python.pycode._pyx331.f$0(<event:mouseEntered>:77)
at org.python.pycode._pyx331.call_function(<event:mouseEntered>)
at org.python.core.PyTableCode.call(PyTableCode.java:165)
at org.python.core.PyCode.call(PyCode.java:18)
at org.python.core.Py.runCode(Py.java:1275)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:623)
at

[/quote]

When I print out the comp.properties(), it shows the following.

array(com.inductiveautomation.factorypmi.application.binding.DynamicPropertyDescriptor, [IsSelected, NotSelectedColor, SelectedColor])

Note that the IsSelected property is there, except that I cannot assign it with the way I show above. How do I do that?

I start to get confused about ā€œAttributeā€ and ā€œPropertyā€ hereā€¦

Update:

When I try to get the property IsSelected from the ā€œarrayā€(?) by:

comp.properties['IsSelected'] = True

It generates error saying: ā€œThe array index must be integerā€.

OK make sense, so I change the above code to get the index 0 property since it is where the IsSelected is property is:

comp.properties[0] = True

But it generates another error:

[quote]TypeError: canā€™t convert True to com.inductiveautomation.factorypmi.application.binding.DynamicPropertyDescriptor

at org.python.core.Py.TypeError(Py.java:235)
at org.python.core.Py.tojava(Py.java:515)
at org.python.core.PyArray.pyset(PyArray.java:1472)
at org.python.core.PySequence$1.setItem(PySequence.java:431)
at org.python.core.SequenceIndexDelegate.checkIdxAndSetItem(SequenceIndexDelegate.java:46)
at org.python.core.SequenceIndexDelegate.checkIdxAndSetItem(SequenceIndexDelegate.java:28)
at org.python.core.PySequence.seq___setitem__(PySequence.java:360)
at org.python.core.PySequence.__setitem__(PySequence.java:356)
at org.python.pycode._pyx348.f$0(<event:mouseEntered>:78)
at org.python.pycode._pyx348.call_function(<event:mouseEntered>)
at org.python.core.PyTableCode.call(PyTableCode.java:165)
at org.python.core.PyCode.call(PyCode.java:18)
at org.python.core.Py.runCode(Py.java:1275)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:623)

[/quote]

I run out of bullet hereā€¦

Hi pturmel,

In the end I try to inspect the component using the inspect.py (java.reflection()) which you created and manage to figure out that there is a setPropertyValue() method there. I use it to set my propertyā€™s value and it is now OK.

Thanks! It is really helpful! :smiley:

getPropertyValue() and setPropertyValue() are documented in the Ignition Manual. They used to be needed everywhere when accessing custom properties of components, but IA tweaked their event routines to coerce python to access them just like built-in properties. At least for event.source, chains of .getComponent() on event.source, and ā€˜selfā€™ in custom component methods.
{ I havenā€™t figured out how they did it ā€“ Iā€™d like to apply that treatment to ā€˜binding.targetā€™ in my Simulation Aids moduleā€™s expression functions. }

Now that you mention it, I started to recall somewhere in my memory that there was such thing in the Inductive University video. I must really have forgotten it... :S still, thanks a lot for your help!

Note for future archeologists... the python wrapper behavior has been deciphered... see this post: