Component and Window Scripting
A lot of the scripting that happens in Ignition is either located on components and windows, or manipulates component and window values. Many times, the property selector () button is available to allow you to easily add in the path to another component or property from your script. However, there are also places where the property selector is not available, but you may still want to access specific components or properties. So it is important to understand how the component hierarchy of a window works as well as how to properly access components and properties in a script anywhere in a project.
Component Hierarchy
Every window in a project has a hierarchy to it, with components and containers arranged in a tree structure, with a single parent up at the top, and many children down at the bottom. While small windows with only a few components can have a simple hierarchy, windows with many containers can get much more complex. Since the components are arranged like a tree, this means that we can only move up and down through the tree structure and not sideways. To get from one component to a sibling component, we must first navigate up towards the common parent, and then back down to the desired child. Let's take a look at an example of how this works. Here we have a simple window, with just a few components:
- Root Container
- Edit Table Container
- New Value Text Field
- Enter Data Button
- Alarm Label
- Data Table
- Header Label
- Edit Table Container
We can flip the tree around to get a better understanding of exactly how the tree works:
Here we can get a better idea of why we can only move up and down through the tree structure, and how getting to a component can be very different depending on where you start. Let's say we want to go to the New Value Text Field so that we can grab its value.
Start From | Path To New Value Text Field |
---|---|
Edit Table Container | 1. Down to New Value Text Field |
Enter Data Button | 1. Up to Edit Table Container 2. Down to New Value Text Field |
Data Table | 1. Up to Root Container 2. Down to Edit Table Container 3. Down to New Value Text Field |
To move up or down within the hierarchy, there are two special commands we can use on component objects: parent and getComponent(). The parent property allows us to grab a reference to whatever is directly above the component in the hierarchy, which in most cases is the Root Container. We could then access any component on the Root Container using getComponent("Component Name") and placing the name of the component we want to access within the parenthesis.
# This pseudo code shows how to grab the parent of a component
component.parent
# This pseudo code shows how to grab a child of a component
component.getComponent("Text Field")
Both parent and getComponent() can be used as many times as necessary to reach the desired component, drilling up or down through layers of containers or or grouped components. Once you have a component reference, you can then access any one of that component's attributes by using the name of the property, just like when accessing a property on the source component.
There is one exception to the pattern of using .parent
to go up the hierarchy and using .getComponent(name)
to go down. The parent of a root container is not the window, and a reference to the window does not have a .getComponent(name)
function. To get a reference to a window, simply use system.gui.getParentWindow with any component's event
object as the parameter. Once you have a reference to a window, you can use its .rootContainer
property to get to the root of the component hierarchy, and from here you can follow the rules laid out above.
Accessing Component Properties
Accessing Component Properties
Watch the videoTo access a property within the component, we simply need to use the scripting name of the property. The scripting name can be found in the description of each property, either by enabling the description field or hovering over the property until the mouseover text appears. The scripting names for every property on every component can also be found in the appendix. For a text field, the scripting name of the text property is just text, so we would need to call that on the text field which has the text property we want to access.
# This pseudo code will access the text property of a component and assign it to value.
value = component.text
Accessing a Component
Now that we have an understanding of how the component hierarchy works, we can apply that knowledge to accessing a component from anywhere within the project. While moving up and down within the hierarchy remains the same, accessing our initial component can differ depending on where we start our script from.
From an Event Handler
Event Handlers get a special event object that has special properties depending on the type of event. Regardless of the event, all event objects have a source property, which gives the component that fired the event. When accessing a component from an event handler, we can first use event.source
to get a component on the window to start at. From there, we can use parent or getComponent() as needed to get to the component we need to access.
# This would access the text property of a Text Field component.
print event.source.parent.getComponent('Text Field').text
When accessing a component from an event on the window, there will be a different path to the component than normal. If you already have a window object, you can use the function getComponentForPath(). This allows you to enter in the path to the component as a string (similar to expression bindings), and will end up looking something like this:
system.gui.getParentWindow(event).getComponentForPath('Root Container.Text Field').text
You can also get the Root Container directly using the getRootContainer() function. This link of code works the same as the one above:
system.gui.getParentWindow(event).getRootContainer().getComponent('Text Field').text
From an Extension Function
Extension Functions get a special self object which is actually a direct reference to the component that the extension function is on. This provides a direct reference point from which to access other components within the component hierarchy.
# This would access the text property of the component running the extension function script.
print self.text
# This would access the text property of the component named 'Text Field' if it is in the same container.
print self.parent.getComponent('Text Field').text
From a Client Event Script
Client Event Scripts are special because they don't start with a direct reference to anything on a particular window. So, we have to use another means of finding a starting point on the window. The system.gui.getWindow() function allows us to get a reference to a window which we can use to navigate to the root container with .getRootContainer()
, and then to any component on that window. However, this will only work if the window is currently opened. If the window is closed, it will throw an error, which can be handled with normal exception handling.
# Start the try block in case the window is not open.
try:
# Grab the window reference and assign it to the variable window.
window = system.gui.getWindow("Other Window")
# Use the window reference to get the text property off of a text field.
print window.getRootContainer().getComponent("Text Field").text
# Handle the exception by opening an informative error.
except ValueError:
system.gui.errorBox("The window is not open!", "Error")
From a Project or Shared Script
Project and Shared Scripts are unique in that how they access components can vary depending on where the Script Module is being called from and what is being passed to it. If the script module is being called from an event handler or an extension function, it is possible to pass in the event or self objects and use them within the script module.
# This code would go in a project script. We are defining our function that takes an event object
# and uses it to find the value of the text property on the text field in the same container.
def func(event):
print event.source.parent.getComponent('Text Field').text
# On the action performed of a button on our window, we could then use this to call our function.
project.myScript.func(event)
However, this may not always be the case. In these instances, it is possible to instead use the same method that Client Event Scripts use and grab the window object instead.
Accessing Components on Other Windows
Finding Components on Other Windows
Watch the videoYou can also grab properties from components on other open windows from anywhere in the project using the same method used in Client Event Scripts. This allows you to grab properties on a main window from an event handler on a popup window.
Remember, you can only grab a property from another window if the other window is open.