Bound Tag Path from Display Component in Script

Hi,

I am quite stumped on this and don't know if it's even possible, but any help will be greatly appreciated.

I have a display component on my window, a numeric label. I have the number label binded to a tag - lets call it tag\testtag. The value of testtag is 110.

In a script, I am trying to pull the tag and/or the tag path binded to my numeric label such that when a particular event is fired I am able to dislpay what the numeric label is binded too.....

Any help on this would be fantastic! :unamused:

1 Like

I thought I would share my solution in case it’s useful for anyone still looking to achieve this.
The script returns the tag path of a tag that a property is bound to using tag binding or indirect tag binding.
Pass in the component and the name of the property that you want the corresponding tag path for.
It was written for 7.9.4

# --------------------------------------------------------------------------
# Get the path of the tag that a component's property is bound to.
# --------------------------------------------------------------------------
def getTagForProperty(component, property="value"):
	# Get the window for this component
	window = component
	while window != None and not window.class.simpleName in ("FPMIWindow", "VisionTemplate"):
		# Keep checking the parent until we find an FPMIWindow
		window = window.parent
	if window != None:
		# Get all the binding adapters on the window for the given component.
		for a in window.getInteractionController().getAllAdaptersForTarget(component):
			# Check the property binding adapters for one that matches the given property name
			if a.getTargetPropertyName() == property:
				if a.class.simpleName == "SimpleBoundTagAdapter":
					return a.getTagPathString()
				elif a.class.simpleName == "IndirectTagBindingAdapter":
					# Parse the indirect tag path
					interactions = a.getInteractions()
					ss = [] # List of parts of the string that will be returned
					for p in a.getPathParts():
						idx = p.getRefIdx()
						if idx > 0:
							# Get the current value of indirect bindings
							ss.append(interactions[idx - 1].getQValue().value)
						else:
							# Get static strings
							ss.append(p.getString())
					return "".join(ss)	
				break # The property was found but it is not bound to a tag
	# Return None if no tag binding was found
	return None

You can skip the loop through all property adapters… the interaction controller has a specific method to yield the binding on a component property.

1 Like

I altered the script to recursively check property bindings.
So if property1 is bound to property2, and property2 is bound to a tag, calling the script for property1 will return the tag path on property2.

# --------------------------------------------------------------------------
# Get the path of the tag that a component's property is bound to.
# --------------------------------------------------------------------------
def getTagForProperty(component, property="value"):
	# Get the window for this component
	window = component
	while window != None and not window.class.simpleName in ("FPMIWindow", "VisionTemplate"):
		# Keep checking the parent until we find a window (or template)
		window = window.parent
		
	if window != None:		
		# Get the binding adapter on the window for the given component and property.
		ic = window.getInteractionController()
		adapter = ic.getPropertyAdapter(component, property)
		
		if adapter != None:
			# Simple Tag Binding
			if adapter.class.simpleName == "SimpleBoundTagAdapter":
				return adapter.getTagPathString()
			# Indirect Tag Binding
			elif adapter.class.simpleName == "IndirectTagBindingAdapter":
				# Parse the indirect tag path
				interactions = adapter.getInteractions()
				ss = [] # List of parts of the string that will be returned
				for p in adapter.getPathParts():
					idx = p.getRefIdx()
					if idx > 0:
						# Get the current value of indirect bindings
						ss.append(interactions[idx - 1].getQValue().value)
					else:
						# Get static strings
						ss.append(p.getString())
				return "".join(ss)
			# Property Binding
			elif adapter.class.simpleName == "SimpleBoundPropertyAdapter":
				interaction = adapter.getInteraction()
				# Recursively check if source property is bound to a tag
				return getTagForProperty(interaction.getSource(), interaction.getSourceProperty())
		
	# Return None if no tag binding was found
	return None
3 Likes

Can you give an example of how to use this script?
Where does this code have to be paste?

Here is a simple example that runs the script when a button is pressed to display the tag path of the binding on the LED Display component.
First, create a custom method on the button for the script (see screenshot). Then, in the actionPerformed event handler on the button, call the custom method:

tag = event.source.getTagForProperty(event.source.parent.getComponent('LED Display'), 'value')
event.source.parent.getComponent('Label').text = tag

Note, this was created in Ignition 7.9 vision module.

Very cool, I was looking for something like this ages and ages ago. Pity it's not possible in Perspective as well :frowning: This is the stuff I miss being able to do in Perspective compared to Vision, without of course making your own module. Unfortunately I have 0 typescript, javascript, react, and 5/100 java experience

For expression bindings you can add this to get the expression itself, not sure yet how to pull out direct tag references, although I don’t think you can rely on that as they could be dynamically created e.g. with tag(), although I guess these would have to be translated into the tag itself…

elif adapter.class.simpleName == "ExpressionPropertyAdapter":
	return adapter.expressionSource

Is it possible to do this is a template? I would like to add this code
to my templates to allow the user to get the tag path when clicked.

Should work. I recommend replacing the type check for FPMIWindow, VisionTemplate with the single BindingRoot interface. And the whole thing should be moved to a project library script. It is terribly inefficient to have such code in your actual events.

thanks for the fast reply, Did I do this right?
while window != None and not window.class.simpleName in ("BindingRoot"):
I cound not get it to work in a template.
Thanks

I did get this to work
while window != None and not window.class.simpleName in ("FPMIWindow", "VisionTemplate","BindingRoot"):
Is there anything wrong with leaving the code in the template, other than it is repeated every time
i use the template, I don't won't a dependency on code in the project.

Thanks so Much for your help

Whoops! No, I was thinking of the actual BindingRoot interface object, used with jython's isinstance() function, or better, replace the whole loop with SwingUtilities.getAncesterOfClass().

1 Like

It'll work, but will bloat your project and become a maintenance nightmare if used elsewhere. Make a project library script.

Thanks pturmel
This will really help

anyone have an example of this working in 8.1 (vision)? trying to find the tagpath that is bound to a template parameter. I've been playing around with this, but it keeps returning None.