Template Repeater with a check box in the template

Firstly, I make a vision template, with only one check box in it. and defined two Template Parameters which bidirectional binding to the Text property and Selected property of this check box.

Then I make a template repeater in a vision window, for this template repeater, I change the template path to above template, change repeat behavior to Dataset mode; binding the Template Parameters to a dataset which is a customer property of that window’s root container. This dataset is with only two columns, one column is the number to indicate the check box text, and the other column to indicate the check box is selected or not. I set them all unselected at beginning, Then in preview mode, I selected some of the check box, I thought the dataset will also changed, but they are not changing.

Seems the dataset can only be passed in a single direction from template repeater to template, when it is changed in template, it will not change back to template repeater.

I can only use script to access the inner template to get the information I want.

templateRepeater = event.source.parent.getComponent('Template Repeater')
templates = templateRepeater.getLoadedTemplates()

for template in templates:
    print 'text is ',template.getComponent('CheckBox').text, ';  selected is ',   template.getComponent('CheckBox').selected
`

I’m not sure if there is any other method to pass the information back from template back to template repeater.

image

Correct.

You can use scripting to 'reference' the parent component (the template repeater) and/or the window above it, either by chaining successive parent calls or importing SwingUtilities. There are some examples on the forum if you search for 'template access parent' or similar.

1 Like

Thank you. I tested that I can access back to the template repeater, or the windows’ root container by repeat .parent several times.

print '\nlevel1:'
print event.source
print type(event.source)

print '\nlevel2:'
print event.source.parent
print type(event.source.parent)

print '\nlevel3:'
print event.source.parent.parent
print type(event.source.parent.parent)

print '\nlevel4:'
print event.source.parent.parent.parent
print type(event.source.parent.parent.parent)

print '\nlevel5:'
print event.source.parent.parent.parent.parent
print type(event.source.parent.parent.parent.parent)

print '\nlevel6:'
print event.source.parent.parent.parent.parent.parent
print type(event.source.parent.parent.parent.parent.parent)

print '\nlevel7:'
print event.source.parent.parent.parent.parent.parent.parent
print type(event.source.parent.parent.parent.parent.parent.parent)

print '\nlevel8:'
print event.source.parent.parent.parent.parent.parent.parent.parent
print type(event.source.parent.parent.parent.parent.parent.parent.parent)

And it prints out the details of the hierarchy. I can use it to access back to template repeater or root container.

level1:
com.inductiveautomation.factorypmi.application.components.PMICheckBox[CheckBox,0,0,43x18,alignmentX=0.0,alignmentY=0.5,border=javax.swing.border.EmptyBorder@2fad08a2,flags=352,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=0,left=0,bottom=0,right=0],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=1]
<type 'com.inductiveautomation.factorypmi.application.components.PMICheckBox'>

level2:
Cavity Selector
<type 'com.inductiveautomation.factorypmi.application.components.template.VisionTemplate'>

level3:
com.inductiveautomation.factorypmi.application.components.TemplateRepeater$FlowVerticalView[,0,0,375x180,layout=com.inductiveautomation.ignition.client.util.gui.VerticalScrollingFlowLayout,alignmentX=0.0,alignmentY=0.0,border=javax.swing.plaf.synth.SynthBorder@26657e3d,flags=16777217,maximumSize=,minimumSize=,preferredSize=]
<type 'com.inductiveautomation.factorypmi.application.components.TemplateRepeater$FlowVerticalView'>

level4:
javax.swing.JViewport[,0,0,375x186,layout=javax.swing.ViewportLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=25165824,maximumSize=,minimumSize=,preferredSize=,isViewSizeSet=true,lastPaintPosition=java.awt.Point[x=0,y=0],scrollUnderway=false]
<type 'javax.swing.JViewport'>

level5:
com.jidesoft.swing.JideScrollPane[,0,0,375x186,layout=com.jidesoft.swing.JideScrollPaneLayout$UIResource,alignmentX=0.0,alignmentY=0.0,border=,flags=16777536,maximumSize=,minimumSize=,preferredSize=,columnHeader=,horizontalScrollBar=javax.swing.JScrollPane$ScrollBar[,0,0,375x0,hidden,layout=javax.swing.plaf.synth.SynthScrollBarUI,alignmentX=0.0,alignmentY=0.0,border=javax.swing.plaf.synth.SynthBorder@57905cca,flags=4194560,maximumSize=,minimumSize=,preferredSize=,blockIncrement=10,orientation=HORIZONTAL,unitIncrement=1],horizontalScrollBarPolicy=HORIZONTAL_SCROLLBAR_AS_NEEDED,lowerLeft=,lowerRight=,rowHeader=,upperLeft=,upperRight=,verticalScrollBar=javax.swing.JScrollPane$ScrollBar[,0,0,0x0,hidden,layout=javax.swing.plaf.synth.SynthScrollBarUI,alignmentX=0.0,alignmentY=0.0,border=javax.swing.plaf.synth.SynthBorder@5604662e,flags=4194560,maximumSize=,minimumSize=,preferredSize=,blockIncrement=10,orientation=VERTICAL,unitIncrement=1],verticalScrollBarPolicy=VERTICAL_SCROLLBAR_AS_NEEDED,viewport=javax.swing.JViewport[,0,0,375x186,layout=javax.swing.ViewportLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=25165824,maximumSize=,minimumSize=,preferredSize=,isViewSizeSet=true,lastPaintPosition=java.awt.Point[x=0,y=0],scrollUnderway=false],viewportBorder=javax.swing.plaf.synth.SynthScrollPaneUI$ViewportBorder@1d13024f]
<type 'com.jidesoft.swing.JideScrollPane'>

level6:
com.inductiveautomation.factorypmi.application.components.TemplateRepeater[Template Repeater,4,48,375x186,layout=com.inductiveautomation.ignition.client.util.gui.FillingLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]
<type 'com.inductiveautomation.factorypmi.application.components.TemplateRepeater'>

level7:
Root Container
<type 'com.inductiveautomation.factorypmi.application.components.BasicContainer'>

level8:
javax.swing.JLayeredPane[null.layeredPane,0,0,384x297,alignmentX=0.0,alignmentY=0.0,border=,flags=0,maximumSize=,minimumSize=,preferredSize=,optimizedDrawingPossible=true]
<type 'javax.swing.JLayeredPane'>
1 Like

I find this approach looks cleaner, and it will continue to work even if the internal template component gets moved around:

from javax.swing import SwingUtilities
from com.inductiveautomation.factorypmi.application.components import TemplateRepeater

repeater = SwingUtilities.getAncestorOfClass(TemplateRepeater, event.source)
1 Like

Awesome! SwingUtilities.getAncestorOfClass(Class c, Component comp) is a good method to find the first parent instance of a specific class. I only need remember and import the correct class.

for my case, I want to get the Root Container (the parent of template repeater), I just need to change the second import.

from javax.swing import SwingUtilities

from com.inductiveautomation.factorypmi.application.components import BasicContainer

rootContainer = SwingUtilities.getAncestorOfClass(BasicContainer, event.source)   

It also works well.

And use this method, it will not break the chain if the components move around.

If the source component is ever nested in a container, this script will not find the root container first. However, if the root container is all you need, the code is much simpler and doesn't require any imports:

# Get the root container the event occured in from the parent window
rootContainer = system.gui.getParentWindow(event).rootContainer
2 Likes

Yes, you are right. Your script provides another method for my use case.

Now I understand both:

  1. How to access the internal instance of templates when I’m outside in a template repeater/ canvas / window
  2. How to access the outside template repeater / canvas when I’m in a template instance
2 Likes