Ignition - Table Component: Scroll Bar Hide & Selected Row

I have two questions that are related that I am hoping the forum has some answers to.

1.) With the Table Component in Ignition, is there a way to hide the vertical and horizontal scroll bars? The application for this is on mobile platforms where the scroll bars are difficult or not practical to use, so I would like to remove this option.
2.) Building Scroll Buttons: I tried to implement a Scroll Up/Down set of buttons to move through the dataset in a Table Component, but noticed that if I iterate the Selected Row property of the Table Component, the behavior of the row selected depends on which column the data is sorted on. The result is unpredictable behavior for the user as they press the Up/Down scroll buttons. Is there a better way to accomplish the Up/Down function that I am after?

See attached picture for (hopefully) some better insight in to what I am talking about.

Thanks in advance, Mudbay


I know It’s been forever since you posted this but just curious if you found a solution to your problem?
Also, if the touch screen mode is enabled under Property Editor, shouldn’t the user be able to press anywhere on the table and be able to move it up and down or left and right?

No resolution to the problem yet. In answer to your question the Property is set for TouchScreen (as far as I can tell).

As for the second part to your question, I was hoping I could navigate using touch on the table, but I don’t think “multi-touch” is supported and the Scroll Bar is a little difficult for users to use. I was going to add the Up/down buttons to make it easier. However, that led to another issue for me.

Any further thoughts you may have on what I may be doing wrong or a work around, would be greatly appreciated.


The following code will allow you to use a button to scroll a table one row at a time.

table = event.source.parent.getComponent('Table 1') rowHeight = table.getRowHeight() scrollBar = table.getVerticalScrollBar() scrollBar.setValue(scrollBar.getValue() + rowHeight)

4 Likes

For the scrollbars:

from javax.swing import JScrollPane
table = event.source.parent.getComponent('Table')
table.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)
table.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER)

Edit: Here’s a better way to do it. There is no need to need to import the JScrollPane class, only need the ScrollPaneConstants.

from javax.swing import ScrollPaneConstants
table = event.source.parent.getComponent('Table')
table.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)
table.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER)
3 Likes

[quote=“Pat”]The following code will allow you to use a button to scroll a table one row at a time.

table = event.source.parent.getComponent('Table 1') rowHeight = table.getRowHeight() scrollBar = table.getVerticalScrollBar() scrollBar.setValue(scrollBar.getValue() + rowHeight)[/quote]
Great stuff Pat, I was able to make a up and down and also PgUp and PgDn but I got a question, how do I go about setting it so the scrollbar keeps moving when I hold the mouse button? right now you pretty much have to click every time for it to move. I know there are altDown, controlDown and shiftDown in event object properties but nothing about mouse button hold. :scratch:

1 Like

Hey Pat, I was just curious if there is an option for horizontal scrollbar movement like this?

Move that code into a timerscript component.
On the buttons, have some code in the MousePressed / MouseReleased that sets a value somewhere that determines one of the buttons is pressed.
Bind the running property to this value.
Change the delay to adjust speed.

TableScroll_7_9_5.proj (26.2 KB)

1 Like

This is still for vertical movement correct?
any luck on making it move horizontally?

Pat or anyone,
We are using this code to move the scrollbar based on the selectedRow of a table and it works well as is. But what I really need is a way to just keep the scroll (or Selected Row actually) vertically centered in the table so operators can always see the few lines above and below the currently selected row. Table shows five rows, but there are 25 rows total. I wondered if there is a simple method using scrollpanes, but haven’t found that. Any ideas would be appreciated. Obviously when selectedRow<2 would have to ignore any centering logic. This seems related to another topic here Scroll scrollbar to position via script?

When I’m back in the office in a couple hours, I’ll add my other script to my topic you linked which takes the row label you want to jump to as an argument and jumps to it in a list

1 Like

Ok, so after a bit of messing around, I modified my original function to work with both template repeaters and both types of tables (as well as made my previous function more efficient, if you saw the previous version of this post).

Call with E.g.:

scrollableObj = event.source.parent.getComponent('Table')
scrollToPos(scrollableObj, "Col 1", 30) # scroll to (the first) cell value with 30 for column "Col 1"
def scrollToPos(scrollableObj, DataSetFieldName, NewDataSetPosValue, position=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 - item at the top minus 1
								1 - item in the centre
	
	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.
	'''
	objType = str(type(scrollableObj))
	
	#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
	
	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
		tableHeight = scrollableObj.height
		itemHeight = scrollableObj.rowHeight
		itemsInView = tableHeight / 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:
			newPos = int(itemHeight*(index - itemsInView/2))
		else:
			newPos = int(itemHeight*(index-1))
		
		scrollBar.setValue(newPos)

This code actually does exactly what I need and it is very simple.
The selectedRow of a Table can be changed by external actions (not clicked on)
Need to keep the Selected Row centered in the table when not at the extreme limits of the table for ease of viewing by the operators.

# property change logic of a Table Component
# Table -- keep Selected Row centered vertically logic
# the rowCount can change when source data for the table changes.
# the table component size is 16 visible rows.
# when selected Row gets close to either top or bottom limit, then don't adjust scrollbar position
table = event.source
rowHeight = table.getRowHeight()				# Grab rowHeight Property
viewRow = table.selectedRow
rowCount = table.data.rowCount
scrollBar = table.getVerticalScrollBar()			# Grab the Vertical Scroll Bar property
				
if event.propertyName == "selectedRow":
# if rowCount > 16 then scroll, otherwise not needed
# when selectedRow or viewRow >=7, start scrolling until we get within 8 rows of the bottom, then don't scroll
	if rowCount > 16 and viewRow >=0 and viewRow < (rowCount-8):
		if viewRow < 7:
			scrollBar.setValue(0)	
		elif viewRow < (rowCount-8):	
			scrollBar.setValue((viewRow-7)*rowHeight)	

2 Likes

FWIW, I simplified my function after seeing your method to get the scrollbar. I didn’t realise you could just call verticalScrollBar on the table / template repeater itself to get it. I also replaced all functions with their netbeans equivalent to appease @pturmel :smile: and found a function to directly get the item height without having to calculate it.
It doesn’t use a selectedRow as such so isn’t suitable for your application, but it does automatically calculate the centre without hardcoding anything. I always try to write reusable code, as I always end up kicking myself if I don’t when I need to use it for another window.

3 Likes

Where do you put that code at?

I keep getting a scroll bar at the bottom of a table in a perspective view.
Trying to stop it from showing up.

This code was for vision and so will be very different from what would be needed in perspective.

I believe that scroll bars in Perspective would be handled via CSS though I don’t know the selectors and styles right off hand.

1 Like

Here's an extension of JGJohnson's code because setting VERTICAL_SCROLLBAR_NEVER also removes the ability to scroll through rows using the mousewheel. This removes the scrollbar and then re-adds the scrolling listener. You add it to the initialize script of your power table.

# Hide the scroll bar.
from javax.swing import ScrollPaneConstants
self.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER)
	
# Re-enable mouse scroll wheel (disabled after disabling scroll bar).
from java.awt.event import MouseWheelListener
from javax.swing import JTable, JScrollPane
from java.awt import Point
	
class MouseWheelScroller(MouseWheelListener):
	
	def __init__(self, table, viewport):
		self.table = table
		self.viewport = viewport
		self.visible_row = 0
		
	def mouseWheelMoved(self, event):
		
		if event.getWheelRotation() < 0:
			self.visible_row -= 1
		else:
			self.visible_row += 1
	
		self.visible_row = max(0, min(self.visible_row, self.table.data.rowCount))
		self.viewport.setViewPosition(Point(0, self.visible_row * self.table.getRowHeight()))
		event.consume()

viewport = self.getViewport()
self.addMouseWheelListener(MouseWheelScroller(self, viewport))
1 Like

How to use this code, where you have used this?
Can you please little bit more info?

Are you aware that this code is for Vision? It won't work in Perspective.

If you are talking about Ryan Shaw's code [the most recent entry], it belongs in the "initialize" extension function of a power table. If you needed to adapt the code for a regular table component, simply change every instance of self to event.source and nest it in the following if statement: if event.propertyName == 'componentRunning': The code would then be placed in the propertyChange event handler.

If you are talking about anybody else's code, please specify for further guidance.

Edit: Replacing self is for everything outside of the mouseWheelListener class. To eliminate confusion, here is the Ryan Shaw's script converted for use in a regular table:

Converted Script
if event.propertyName == 'componentRunning':
	# Hide the scroll bar.
	from javax.swing import ScrollPaneConstants
	event.source.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER)
		
	# Re-enable mouse scroll wheel (disabled after disabling scroll bar).
	from java.awt.event import MouseWheelListener
	from javax.swing import JTable, JScrollPane
	from java.awt import Point
		
	class MouseWheelScroller(MouseWheelListener):
		
		def __init__(self, table, viewport):
			self.table = table
			self.viewport = viewport
			self.visible_row = 0
			
		def mouseWheelMoved(self, event):
			
			if event.getWheelRotation() < 0:
				self.visible_row -= 1
			else:
				self.visible_row += 1
		
			self.visible_row = max(0, min(self.visible_row, self.table.data.rowCount))
			self.viewport.setViewPosition(Point(0, self.visible_row * self.table.getRowHeight()))
			event.consume()
	
	viewport = event.source.getViewport()
	event.source.addMouseWheelListener(MouseWheelScroller(event.source, viewport))