Click and drag on windows/compents that have scroll bars

Hi,

Is it possible through scripting to use a click and drag feature to navigate through a window or object that has the hability scroll bars? I am using a template canvas object that enables/shows the scroll bars everytime the instances have x and y bigger than the size of the template canvas object. Instead of using scroll bars to search for my template instances, I would like to click and drag.
Is it possible?

This is possible, and I can imagine several ways to approach this with various degrees of complexity. The main question is where to consume the click event. Do you have components in your template that use mouse clicks? Can you share more about the nature of the components that are displayed in the canvas?

Yes. I have a transparent button with the same size as the whole template which has mouse and mouse motion events. The template canvas is in a root container that also has mouse and mouse motion events.

The transparent component is overlaying the template canvas or is it overlaying each template within the canvas? This is import an important distinction because the method for getting the scroll pane differs if it's a parent vs if it's a child.

Also, while this approach is perhaps simpler than adding your own listener(s) at run time, it will consume the mouse event, so in case I wasn't clear in my original question, if there are buttons or components underneath the overlay that need to be clicked, that functionality will break. Is this the case, or will the overlay approach work for your application?

This approach won't work because (again) any inner swing component that is listening for a mouse event will consume the root container's mouse event.

1 Like

It's overlaying each template within the canvas.

Answering to your 2nd question: No. I have a single button in my template, all the other objects are simply for visualization. And in that button I'm only using a 'property change event'

I've developed a way to do this using your specified overlay component.
Here is the result:
Screen Recording 2024-01-19 at 10.17.03 AM

Here is the procedure:
First create project library scripts for locating the template Canvas's
viewport and adjusting its position.
In my project, I simply nested the functions under componentScripts:
image

from javax.swing import SwingUtilities, JViewport
from java.awt import Point

# Function to get the parent viewPosition of a viewport of a given event
def getViewPosition(event):
	return SwingUtilities.getAncestorOfClass(JViewport, event.source).viewPosition
	
# Function to set the view postion during a mouse dragged event according to how far the mouse has moved from its initial position
def setViewPosition(event, x, y, initialMouseX, initialMouseY, initialViewX, initialViewY):
	'''
	Arguments:
		event: a mouse dragged event
		x, y: the calculated coordinates of the event
		...x and y are averaged to smooth out the mouse movemnents
		initialMouseX, initialMouseY: The position of the mouse pointer during the initial mousePressed event
		initioalViewX, initialViewY: the coordinates of the viewport during the initial mousePressed event
	'''
	# Get the parent viewport of the component the event originated from
	viewport = SwingUtilities.getAncestorOfClass(JViewport, event.source)
	
	# Calulate each coordinate by adding the difference between the current coordinate position and the initial coordinate position to the initial coordinate position
	# ...Make sure the new position is not out of bounds using max and min
	newX = max(0, min(initialViewX + (initialMouseX - x), viewport.view.width - viewport.viewRect.width))
	newY = max(0, min(initialViewY + (initialMouseY - y), viewport.view.height - viewport.viewRect.height))
	
	# Set the new view postion
	viewport.setViewPosition(Point(newX, newY))

Next, add the following custom properties the template overlay:
image

This script is needed on the overlay's mousePressed event to capture initial positions:
image

# Capture and set the initial values of the mouse event on the overlay's custom properties
viewPosition = componentScripts.getViewPosition(event)
event.source.initialMouseX = event.x
event.source.initialMouseY = event.y
event.source.oldX = event.x
event.source.oldY = event.y
event.source.initialViewX = viewPosition.x
event.source.initialViewY = viewPosition.y

Finally, add this script to the overlay component's mouseDragged event handler:
image

# Calculate the event coordinates by averaging the current position and the previous position
# During initial testing, the scroll movements were jittery, but
# ...adding this smoothed the movements out
eventX = (event.x + event.source.oldX)/2
eventY = (event.y + event.source.oldY)/2

# Call the setViewPosition library script to move the viewport
componentScripts.setViewPosition(event, eventX, eventY, event.source.initialMouseX, event.source.initialMouseY, event.source.initialViewX, event.source.initialViewY)

# Update the oldX and oldY properties with this iterations averaged value
event.source.oldX = eventX
event.source.oldY = eventY
2 Likes

The code you provided me works perfectly!!! Thank you!
Although I found a problem due to my application. Sometimes, my template canvas viewport doesn't have any of my template instances showing which is very difficult to click and drag. What do I need to do to have the same effect of click and drag but instead of needing a template instance, any point in the canvas would work

There are so many ways to approach this, but it sounds like the overlay should be over the template canvas instead of over the templates in the canvas. If the overlay were moved to over the canvas and the overlay over the template was done away with, the only difference would be getting the viewport. This could be done with a library script or a custom method on the overlay itself.

Here is how the viewport could be obtained from using a custom method on the canvas overlay:

# def getViewportFromCanvas(self, canvas):
	for component in canvas.components:
		if component.__class__.__name__ == 'TemplateCanvas$1':
			return component.viewport

To move the scrollbars:
On the mousePressed event:

# get the template canvas
canvas = event.source.parent.getComponent('Template Canvas')

# Capture and set the initial values of the mouse event on the overlay's custom properties
viewPosition = event.source.getViewportFromCanvas(canvas).viewPosition
event.source.initialMouseX = event.x
event.source.initialMouseY = event.y
event.source.oldX = event.x
event.source.oldY = event.y
event.source.initialViewX = viewPosition.x
event.source.initialViewY = viewPosition.y

On the mouseDragged event:

from java.awt import Point

# Get the canvas and its viewport
canvas = event.source.parent.getComponent('Template Canvas')
viewport = event.source.getViewportFromCanvas(canvas)

# Calculate the event coordinates by averaging the current position and the previous position
# During initial testing, the scroll movements were jittery, but
# ...adding this smoothed the movements out
eventX = (event.x + event.source.oldX)/2
eventY = (event.y + event.source.oldY)/2

# Calulate each coordinate by adding the difference between the current coordinate position and the initial coordinate position to the initial coordinate position
# ...Make sure the new position is not out of bounds using max and min
newX = max(0, min(event.source.initialViewX + (event.source.initialMouseX - eventX), viewport.view.width - viewport.viewRect.width))
newY = max(0, min(event.source.initialViewY + (event.source.initialMouseY - eventY), viewport.view.height - viewport.viewRect.height))

# Set the new view postion
viewport.setViewPosition(Point(newX, newY))

# Update the oldX and oldY properties with this iterations averaged value
event.source.oldX = eventX
event.source.oldY = eventY
1 Like

what is the origin of those space ships :eyes:

It was a demo I put together to showcase my Component Spotlight resource's ability to move scroll bars in order to spotlight components that are off screen.

Pretty sure it's this one:

1 Like

It's not that one.

The templates I used to create the ships were obtained from this image:

image

Appropriately named path based vision shapes were used to autopopulate the dropdown with spotlightable components.

The space background is just some arbitrary image of space. The oversized image and canvas backgrounds were made transparent, and the space background was layered underneath. This is why when the ships move in the scroll pane, the movement is contrasted by the static space background.

It's a cool look. I liked the way it turned out:
Screen Recording 2024-01-19 at 10.17.03 AM

2 Likes

Both those ways work perfectly! Thank you so much for the trouble. You saved me quite some hours!

1 Like