When I need to get a certain type of parent from a generic component such as a template, and I can't predict how deeply the component will be nested from one instance to the next, I simply obtain the parent with swing utilities because it's simpler and cleaner than a recursive script. However, every now and then, I find myself retrieving a parent component with a custom method or property that I need to call or manipulate, and if I use swing utilities, I find that the custom attributes are lost.
Obviously, this is not a show stopper because this scenario doesn't occur very often, and when it does, I can simply use a recursive function instead, but I'm curious why this is, and if there is a simple work around.
Custom properties are added to the java standard jython conversion by IA's PyComponentWrapper. For a complete discussion, read this entire topic:
TL/DR: Install my Simulation Aids module to magically fix this, everywhere in Ignition. There is no other solution until IA eventually does this first party.
Thanks for the hint. Wrapping the swing utility call in the PyComponentWrapper returns the object with the custom properties accessible.
Just for completeness and clarity; the recursive approach always works for returning a component with its custom properties.
Recursive example to get the parent container of a component:
from com.inductiveautomation.factorypmi.application.components import BasicContainer
def getParentContainer(component):
if isinstance(component.parent, BasicContainer):
return component.parent
else:
parentContainer = getParentContainer(component.parent)
if parentContainer is not None:
return parentContainer
parentContainer = getParentContainer(event.source)
The getAncestorOfClass approach returns the expected component and takes far fewer lines of code, but all custom properties are lost:
Basic SwingUtilities Example:
from com.inductiveautomation.factorypmi.application.components import BasicContainer
from javax.swing import SwingUtilities
parentContainer = SwingUtilities.getAncestorOfClass(BasicContainer, event.source)
By simply wrapping the swing utility call in a pyComponentWrapper call, the component is returned with the custom properties just like the recursive approach.
pyComponentWrapper with SwingUtilities example:
from com.inductiveautomation.factorypmi.application.components import BasicContainer
from com.inductiveautomation.factorypmi.application.script import PyComponentWrapper
from javax.swing import SwingUtilities
parentContainer = PyComponentWrapper(SwingUtilities.getAncestorOfClass(BasicContainer, event.source))
It's only one more line of code, and it's still cleaner looking than building a recursive function.