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)
[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]
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
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.
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)
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.
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!