Scroll TabStrip to active/selected tab - Vision

I have a TabStrip with 18 tabs.
The popup, where the TabStrip is used is not big enough to show complete TabStrip, so the arrows are shown on the right side.
If I set the active tab (when the popup is opened, via window parameter) to the tab, that is 'beyond' navigation arrows, is it possible somehow to 'auto scroll' to this selected/active tab, which is currently not visible?
Screenshot_tabstrip1

Screenshot_tabstrip2
I'm/was playing with 'tabStrip.scrollRectToVisible' (like with the tables) but I had no success...

Nobody...?
I was humbly hoped that at least @justinedwards.jle has some info... :pray:

1 Like

I'm not sure the best way to approach this. That component doesn't use a scroll pane, so it's basically just a jpanel nested inside a jpanel. The outer panel will have a layout manager that dictates where the inner panel is positioned. My inclination is to leave that alone and manipulate the position of the inner panel the natural way with the buttons, albeit programmatically. I imagine this could be done with a loop that checks a given tab component's bounds against the tab holder panel's visible rectangle.

1 Like

Thank you for your (always) valuable input...

I guess that is a 'little' out of my league... :innocent:

1 Like

haha, ...okay, this idea seems useful, so I'll develop the prototype

I've tested the following code, and it works:

# Written for the propertyChange event handler of the tab strip
# Evaluates only when the selected tab changes
if event.propertyName == 'selectedTab':
	from java.awt.event import MouseEvent
	
	# Get the panels, the buttons, and the selected tab component
	arrowPanel, tabHolderPanel = event.source.components
	leftButton, rightButton = arrowPanel.components
	selectedTab = next(component for component in tabHolderPanel.components if component.selected)
	
	# Determine which if any button would need to be pressed to bring the selected tab view
	if not tabHolderPanel.visibleRect.contains(selectedTab.bounds):
		if tabHolderPanel.visibleRect.x < selectedTab.x:
			button = rightButton
		else:
			button = leftButton
	else:
		button = None
	
	# If needed, recursively schedule button clicks until the selected tab comes into view
	if button:
		def setPosition():
			releaseEvent = MouseEvent(button, MouseEvent.MOUSE_RELEASED, 0, 0, 0, 0, 1, False)
			button.dispatchEvent(releaseEvent)
			if not tabHolderPanel.visibleRect.contains(selectedTab.bounds):
				system.util.invokeLater(setPosition)
		setPosition()

Please share the final version when you're done golfing and streamlining it.

1 Like

You did it again. Kudos to you.
giphy
I didn't need to change anything from your code. It just worked.
I just moved the code to the project library, because I have a few tabStrips in my project.
This is what I have on the tabStrip propertyChange event:

if event.propertyName == "componentRunning" and event.newValue:
	tabStrip = system.gui.getParentWindow(event).getComponentForPath('Root Container.Tab Strip')
	various_functions.tab_strip.tabStripArrowEditor(tabStrip)

if event.propertyName == 'selectedTab':
	various_functions.tab_strip.moveToActiveTab(event)

And this is my project library script:

#adjust arrow button size for touch screen
from com.inductiveautomation.factorypmi.application.components.util import HoldDownArrowButton
from com.inductiveautomation.factorypmi.application.components.tabstrip import LeftRightArrowPanel
from java.awt import Dimension
from java.awt.event import MouseEvent

arrowWidth = 50
arrowHeight = 50

def tabStripArrowEditor(tabStrip):
	if tabStrip.componentCount > 0:
		for component in tabStrip.getComponents():
			if isinstance(component, LeftRightArrowPanel):
				size = Dimension(arrowWidth*2,arrowHeight)
				component.setPreferredSize(size)
				component.setSize(size)
				component.background = system.gui.color(230,230,230)
				tabStripArrowEditor(component)
				return
			elif isinstance(component, HoldDownArrowButton):
				size = Dimension(arrowWidth,arrowHeight)
				component.setPreferredSize(size)
				component.setSize(size)
				component.background = system.gui.color(230,230,230)
			else:
				tabStripArrowEditor(component)

def moveToActiveTab(event):
	# Get the panels, the buttons, and the selected tab component
	arrowPanel, tabHolderPanel = event.source.components
	leftButton, rightButton = arrowPanel.components
	selectedTab = next(component for component in tabHolderPanel.components if component.selected)

	# Determine which if any button would need to be pressed to bring the selected tab view
	if not tabHolderPanel.visibleRect.contains(selectedTab.bounds):
		if tabHolderPanel.visibleRect.x < selectedTab.x:
			button = rightButton
		else:
			button = leftButton
	else:
		button = None
	
	# If needed, recursively schedule button clicks until the selected tab comes into view
	if button:
		def setPosition():
			releaseEvent = MouseEvent(button, MouseEvent.MOUSE_RELEASED, 0, 0, 0, 0, 1, False)
			button.dispatchEvent(releaseEvent)
			if not tabHolderPanel.visibleRect.contains(selectedTab.bounds):
				system.util.invokeLater(setPosition)
		setPosition()
		setPosition()	#because I'm using wider arrow keys, I need to call this twice more
		setPosition()

And this is the result:
tabStrip1

Again, thank you very much for you help... :smiley:

2 Likes