# Scroll scrollbar to position via script

**URL:** <https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999>\
**Category:** Ignition\
**Tags:** vision\
**Created:** [November 15, 2017, 6:12am UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999 "2017-11-15T06:12:46Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [November 15, 2017, 6:12am UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/1 "2017-11-15T06:12:46Z")

</div>

I've had a request from a customer to auto-scroll a template repeater to the previous scroll position as left at on the last page view.

How would I go about doing this?

Cheers!

---

<div class="post-metadata">

**Author:** ![Sanderd17](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/sanderd17/32/8735_2.png) [@Sanderd17](https://forum.inductiveautomation.com/u/Sanderd17)\
**Post date:** [November 15, 2017, 9:45am UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/2 "2017-11-15T09:45:47Z")

</div>

Can you get away with just not closing the page (i.e. opening a new page instead of swapping to it)?

The advantage is that switching back to the page will keep it’s old state (switching will become a lot faster too). The disadvantage is that the tags on the page remain active, so keep consuming bandwidth even though they’re not visible.

Depending on what type of page it is, not closing the page may be an acceptable solution.

Otherwise, you can dig into the Java components, and normally get and set the visible rectangle on such a template repeater.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [November 15, 2017, 10:47am UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/3 "2017-11-15T10:47:40Z")

</div>

The actual table pulls in quite a lot of data, so I’m not that keen on keeping this open all the time.

I’ve had a look into the Java components and found the getVisibleRect() and scrollRectToVisible(…) methods. With the following code, I can scroll the Designer’s page frame (???), but in a client runtime, it doesn’t do anything.  
I’ve called this on a button for now:

```auto
me = event.source.parent.getComponent('Template Repeater')

rect = me.getVisibleRect()
print rect
rect.y = rect.y + 10

me.scrollRectToVisible(rect)

```

the print statement in runtime returns: java.awt.Rectangle[x=0,y=0,width=1141,height=685]  
the width and height are the size of the template repeater component, however the me.scrollRectToVisible(rect) call does nothing…  
If I scroll the template repeater manually and run the script again, none of the values change.

What am I doing wrong? P.s. my Java knowledge is very little

Cheers

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [November 21, 2017, 1:26am UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/4 "2017-11-21T01:26:44Z")

</div>

Bump (this is 20 characters)

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [November 24, 2017, 4:33am UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/5 "2017-11-24T04:33:47Z")

</div>

Got it!

```auto
RC = system.gui.getParentWindow(event).rootContainer
me = RC.getComponent('Template Repeater')

#Get the scrollPane object which contains the viewPort object by finding it
components = me.getComponents()
for component in components:
	if str(type(component)) == "<type 'com.jidesoft.swing.JideScrollPane'>":
		scrollPane = component

viewport = scrollPane.getViewport()

#Get the 'visible rectangle' which basically defines the current view of the full scroll-able pane
rect = viewport.getVisibleRect()
#Add '400' units to the horizontal scroll position
rect.y = rect.y + 400

#write the new visible rectangle back to the scroll-able object
viewport.scrollRectToVisible(rect)

```

Thanks for your prompt, Sander

Edit: I replaced the static scrollPane component assignment with a loop to find this component instead, so this should work for any component now and not just the template repeater

---

<div class="post-metadata">

**Author:** ![weertske](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/weertske/32/3353_2.png) [@weertske](https://forum.inductiveautomation.com/u/weertske)\
**Post date:** [March 16, 2018, 11:02pm UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/6 "2018-03-16T23:02:49Z")

</div>

For those who read this thread, a point I learned in applying a derivation of this solution:

You don’t need (or want) “from javax.swing import JScrollPane”, Ignition is using JideScrollPane which is like JScrollPane on steroids. However you can’t import JideScrollPane since it is a licensed package. No problem, it is built into Ignition.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 16, 2018, 11:49pm UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/7 "2018-03-16T23:49:20Z")

</div>

> [@weertske](#):
>
> However you can't import JideScrollPane since it is a licensed package.

Of course you can import it. Import has nothing whatsoever to do with licensing. However, you should never _need_ to, as the ScrollPane already exists in the component, as noted above.

---

<div class="post-metadata">

**Author:** ![weertske](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/weertske/32/3353_2.png) [@weertske](https://forum.inductiveautomation.com/u/weertske)\
**Post date:** [March 17, 2018, 2:14pm UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/8 "2018-03-17T14:14:35Z")

</div>

My bad Phil. I tried to import it and failed and then read it is a licensed package. So I quit and made an inaccurate statement. Thanks for the correction.  
import com.jidesoft.swing.JideScrollPane does work

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [December 14, 2019, 9:52pm UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/9 "2019-12-14T21:52:55Z")

</div>

UPDATED: 2020-06-25

I’ve since created a script library for this (not exactly) function that will scroll to an item in the scrollable component’s dataset:

```auto
# call this on a button or other
scrollableObj = event.source.parent.getComponent('Table')
shared.components.scrollable.scrollToPos(scrollableObj, 'Col 1', 29, 1)

```

```auto
# copy into library: shared.components.scrollable
def scrollToPos(scrollableObj, DataSetFieldName, NewDataSetPosValue, position=0, recursionLevel=0):
	'''
	Description:
	Scrolls the table component to the item above the new position.
	
	Arguments:
	scrollableObj - the scrollable component (table, power table, template repeater - untested with any others)
	DataSetFieldName - the field name in the templateParams dataset to find the new position value in
	NewDataSetPosValue - the field value of the field name to find in the dataset to move to
	Position - the position to scroll to:
								0 - position item at the top minus 1
								1 - position item in the centre
                                2 - position item at the top
	
	Revision:
	No. Date Author Comment
	1.0 2018-11 Nick Minchin	Original
	1.1 2019-12 Nick Minchin	Simplified function. Can set value of scrollbar directly without having to use the viewport.
	1.2 2019-12-15	Nick Minchin	Simplified further method to get the scrollbar object. Added ability to change scroll to position type.
	1.3 2020-06-25	Nick Minchin	Fixed issue with rowHeight for Power Tables. Made item height and items count round up
	'''
	import math
	objType = str(type(scrollableObj))
	
	ds = None
	#get the component's items dataset so that we can work out the current index of the maximum
	if any([t in objType for t in ['PMITable', 'VisionAdvancedTable']]):
		ds = scrollableObj.data
	if any([t in objType for t in ['TemplateRepeater']]):
		ds = scrollableObj.templateParams
	
	if ds == None:
		import sys
		system.gui.messageBox("The object type you passed in is not accounted for. '%s'" % objType, 'Error')
		sys.exit()
	ds = system.dataset.toPyDataSet(ds)
	
	if len(ds) > 0:
		#find the index of the new item from the dataset
		index = 0
		for i in range(len(ds)):
			if ds[i][DataSetFieldName] == NewDataSetPosValue:
				index = i
		
		scrollBar = scrollableObj.verticalScrollBar
		scrollBarHeight = scrollBar.height
		itemHeight = scrollableObj.getTable().getRowHeight(0)
		itemsInView = (1.0*scrollBarHeight) / itemHeight
		
		#Calculate the position of the current step using the item height and the new item's index
		if position == 0:
			newPos = int(itemHeight*(index - 1))
		elif position == 1: #WORKING
			newPos = int(itemHeight*(index + 1 - (itemsInView/2.0)))
			#newPos = int(math.ceil(itemHeight*(index - (itemsInView/2.0))))
		elif position == 2:
			newPos = int(itemHeight*(index - 0))
		else:
			newPos = int(itemHeight*(index - 0))
		
		scrollBar.setValue(newPos)
		scrollableObj.selectedRow = index
		recursionLevel += 1
		# for some reason the first time this is run, the scroll is off by a few pixels.. so call it again
		if recursionLevel == 1:
			scrollToPos(scrollableObj, DataSetFieldName, NewDataSetPosValue, position, recursionLevel)

```

---

<div class="post-metadata">

**Author:** ![fadihindi](https://avatars.discourse-cdn.com/v4/letter/f/34f0e0/32.png) [@fadihindi](https://forum.inductiveautomation.com/u/fadihindi)\
**Post date:** [October 22, 2022, 5:31pm UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/10 "2022-10-22T17:31:55Z")

</div>

I tried using this script on a template repeater, and get the following error: "AttributeError: '[com.inductiveautomation.factorypmi.application.com](http://com.inductiveautomation.factorypmi.application.com)' object has no attribute 'verticalScrollBar'". It looks like from the thread and the script that it is meant to work with a power table or a template repeater. Is there another attribute that would make it work with a template repeater?

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [October 22, 2022, 9:46pm UTC](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/11 "2022-10-22T21:46:21Z")

</div>

> [@fadihindi](#):
>
> Is there another attribute that would make it work with a template repeater?

The code in [post 5](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/5) works perfectly for my template repeater. Is this the code you are using?

> [@Scroll scrollbar to position via script](https://forum.inductiveautomation.com/t/scroll-scrollbar-to-position-via-script/15999/5):
>
> Got it! RC = system.gui.getParentWindow(event).rootContainer me = RC.getComponent('Template Repeater') #Get the scrollPane object which contains the viewPort object by finding it components = me.getComponents() for component in components: if str(type(component)) == "\<type 'com.jidesoft.swing.JideScrollPane'\>": scrollPane = component viewport = scrollPane.getViewport() #Get the 'visible rectangle' which basically defines the current view of the full scroll-able pane rect = viewport.getVis…
