# Synchronize the scroll of two data table contents together and ChangeListener

**URL:** <https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288>\
**Category:** Ignition\
**Tags:** vision\
**Created:** [November 4, 2020, 1:22pm UTC](https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288 "2020-11-04T13:22:37Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![falko](https://avatars.discourse-cdn.com/v4/letter/f/9de0a6/32.png) [@falko](https://forum.inductiveautomation.com/u/falko)\
**Post date:** [November 4, 2020, 1:22pm UTC](https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288/1 "2020-11-04T13:22:37Z")

</div>

Hi all,

I have two tables which i would like to scroll synchronously.  
I am using pturmel’s example ([Freeze table column](http://forum.inductiveautomation.com/t/freeze-table-column/1621)), and everything is working fine.  
But I would like add some point to stop that ChangeListener and break synchronous scrolling two tables. Not sure how to do this. There is removeChangeListener() but i did not figure out how to use it.  
Also, where can be found some details regarding viewport, especially for Table Component (table.viewport)?

Any help is appreciated, thanks!

---

<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:** [November 4, 2020, 1:47pm UTC](https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288/2 "2020-11-04T13:47:13Z")

</div>

You have to pass the listener you want to remove to the removeChangeListener() method. Which means you need to save it somewhere persistent. A [client property](https://docs.oracle.com/javase/8/docs/api/javax/swing/JComponent.html#putClientProperty-java.lang.Object-java.lang.Object-) of the component is probably the best place.

---

<div class="post-metadata">

**Author:** ![falko](https://avatars.discourse-cdn.com/v4/letter/f/9de0a6/32.png) [@falko](https://forum.inductiveautomation.com/u/falko)\
**Post date:** [November 4, 2020, 4:04pm UTC](https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288/3 "2020-11-04T16:04:51Z")

</div>

Thank you ptumel.

I tried client property. I added myScrollEvent to Button\_1, and save it as myClientProperty\_1, and then use another Button\_2, get myClentProperty\_1, print myScrollProperty\_1 (\<function myScrollEvent at 0x2\>), but when i try to remove change listener “tblT22.viewport.removeChangeListener(myScrollEvent)”, nothing happens. Change listener is still active and both table are still scroll synchronously.  
What i am doing wrong?

---

<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:** [November 4, 2020, 5:01pm UTC](https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288/4 "2020-11-04T17:01:15Z")

</div>

Ah, I think you’ll actually have to subclass the ChangeListener interface. I think that happens under the hood if you just add a callable, so the callable isn’t really the ChangeListener. If you subclass it, jython shouldn’t transform it automagically.

---

<div class="post-metadata">

**Author:** ![falko](https://avatars.discourse-cdn.com/v4/letter/f/9de0a6/32.png) [@falko](https://forum.inductiveautomation.com/u/falko)\
**Post date:** [November 5, 2020, 6:55pm UTC](https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288/5 "2020-11-05T18:55:28Z")

</div>

Thank you ptumel.  
It works now. (had to search a little bit about sub-interfaces of EventListener)

---

<div class="post-metadata">

**Author:** ![zxcslo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zxcslo/32/61610_2.png) [@zxcslo](https://forum.inductiveautomation.com/u/zxcslo)\
**Post date:** [November 6, 2020, 5:24am UTC](https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288/6 "2020-11-06T05:24:12Z")

</div>

Care to share the example for the community…?

---

<div class="post-metadata">

**Author:** ![falko](https://avatars.discourse-cdn.com/v4/letter/f/9de0a6/32.png) [@falko](https://forum.inductiveautomation.com/u/falko)\
**Post date:** [November 6, 2020, 1:09pm UTC](https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288/7 "2020-11-06T13:09:46Z")

</div>

hi zxcslo, here is what is use for testing synchronize the scroll of two tables:

> tblT22 = event.source.parent.getComponent('Table 22')  
> tblT12 = event.source.parent.getComponent('Table 12')
> 
> class myListener(ChangeListener):  
> def stateChange(self, e):   
> scrollBarMain = tblT22.getHorizontalScrollBar()  
> scrollBarTop = tblT12.getHorizontalScrollBar()  
> scrollBarTop.setValue(scrollBarMain.getValue())
> 
> #to add ChangeListener  
> tblT22.viewport.addChangeListener(myListener())
> 
> #to remove ChangeListener  
> mls = tblT22.viewport.getChangeListeners()  
> for m in mls:  
> tblT22.viewport.removeChangeListener(m)

---

<div class="post-metadata">

**Author:** ![illank86](https://avatars.discourse-cdn.com/v4/letter/i/c77e96/32.png) [@illank86](https://forum.inductiveautomation.com/u/illank86)\
**Post date:** [December 7, 2023, 12:15am UTC](https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288/8 "2023-12-07T00:15:44Z")

</div>

where should i put this code?

---

<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:** [December 7, 2023, 11:30pm UTC](https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288/9 "2023-12-07T23:30:28Z")

</div>

> [@illank86](#):
>
> where should i put this code

If you're attempting this from Perspective, it won't work. In Vision, if you are using a Power Table, this will work in the `initialize` extension function, and if you are just using a regular Table, this will work from the `componentRunning` `propertyChange` event. _[The componentRunning event will also work on the Power Table]_

**Notes:**  
• If you use the`initialize` extension function, all instances of `event.source` will need to be replaced with `self`.  
• If you are using the `propertyChange` event handler, you can use the code as is, but it needs to be nested in an if statement, or you'll end up with a million listeners on your tables:

```auto
if event propertyName == 'componentRunning':
     # nest the code here

```

• The `componentRunning` event doesn't occur in the designer unless preview mode is started before the window with the script is opened, and the only time I've seen the `initialize` extension function run in the designer has been when my Power Tables are loaded by a temple repeater or canvas , so testing in a session could be necessary for your user case.

---

<div class="post-metadata">

**Author:** ![illank86](https://avatars.discourse-cdn.com/v4/letter/i/c77e96/32.png) [@illank86](https://forum.inductiveautomation.com/u/illank86)\
**Post date:** [December 9, 2023, 1:20am UTC](https://forum.inductiveautomation.com/t/synchronize-the-scroll-of-two-data-table-contents-together-and-changelistener/40288/10 "2023-12-09T01:20:39Z")

</div>

Owh, i thought this is in perspective.. my bad
