# Cursor shape on mouse-over

**URL:** <https://forum.inductiveautomation.com/t/cursor-shape-on-mouse-over/72515>\
**Category:** Ignition\
**Tags:** ignition81, vision\
**Created:** [April 17, 2023, 9:58am UTC](https://forum.inductiveautomation.com/t/cursor-shape-on-mouse-over/72515 "2023-04-17T09:58:42Z")\
**Posts on this page:** 1\
**Showing post:** 7

<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:** [April 19, 2023, 7:21am UTC](https://forum.inductiveautomation.com/t/cursor-shape-on-mouse-over/72515/7 "2023-04-19T07:21:16Z")

</div>

[https://us1.discourse-cdn.com/inductiveautomation/original/3X/3/9/3967fbf401c9cc3e9168d0e081742ca5169c7f05.mp4](https://us1.discourse-cdn.com/inductiveautomation/original/3X/3/9/3967fbf401c9cc3e9168d0e081742ca5169c7f05.mp4)
  
The following script works inside a template:

```auto
	from java.awt import Cursor, MouseInfo
	from java.awt.event import MouseEvent
	from javax.swing import SwingUtilities
	from com.inductiveautomation.factorypmi.application.components import PMIButton, BasicContainer
	from com.inductiveautomation.factorypmi.application.components.template import TemplateHolder
	def getCoordinates(component):
		x1 = component.x
		y1 = component.y
		x2 = component.x + component.width
		y2 = component.y + component.height
		return [x1, y1, x2, y2]
	def isOverlapped(selfCoordinates, componentCoordinates):
		outOfBoundsLeft = (selfCoordinates[2] <= componentCoordinates[0])
		outOfBoundsRight = (selfCoordinates[0] >= componentCoordinates[2])
		outOfBoundsTop = (selfCoordinates[3] <= componentCoordinates[1])
		outOfBoundsBottom = (selfCoordinates[1] >= componentCoordinates[3])
		if outOfBoundsLeft or outOfBoundsRight or outOfBoundsTop or outOfBoundsBottom:
			return False
		else:
			return True
	selfCoordinates = getCoordinates(event.source)
	templateHolder = SwingUtilities.getAncestorOfClass(TemplateHolder, event.source)
	container = SwingUtilities.getAncestorOfClass(BasicContainer, templateHolder)
	for component in container.getComponents():
		if component != event.source and isinstance(component, PMIButton):
			componentCoordinates = getCoordinates(component)
			if isOverlapped(selfCoordinates, componentCoordinates):
				mousePosition = SwingUtilities.	convertPoint(event.source, event.x, event.y, container)
				if mousePosition.x >= componentCoordinates[0] and mousePosition.x <= componentCoordinates[2] and mousePosition.y >= componentCoordinates[1] and mousePosition.y <= componentCoordinates[3]:
					event.source.setCursorCode(Cursor.HAND_CURSOR)
					component.getModel().setRollover(True)
					if event.ID == MouseEvent.MOUSE_CLICKED:
						component.doClick()
				else:
					event.source.setCursorCode(Cursor.DEFAULT_CURSOR)
					component.getModel().setRollover(False)

```

It's the same as the above script except that it gets the template holder first, and then gets the parent container relative to the holder. I also eliminated the getOverlapCoordinates function, since it really wasn't necessary. Due to the fact that events are specific to the component they are firing from, the component coordinates are effectively the same thing.

I put this script in a custom method that I called `evaluateCursorAction`:  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/c/1/c14bf07d89a59e6262f087390e182ec7ada7dda3.png)

This works as expected, but it has to be called independently from the mouseClicked and mouseMoved event handlers on each component within the template that the cursor function is supposed to pass through.

It seemed like it would be a good idea to not use the individual components event handlers, and instead add a custom listener to individual component classes at runtime. In this way, if components within the template get added or replaced, there will be less risk of regression and less technical overhead.

Perhaps such a script would look like this:

> **Automated Listener Application Script**
>
> ```auto
> from java.awt.event import MouseListener, MouseMotionListener
> from com.inductiveautomation.factorypmi.application.components.template import VisionTemplate
> def getTemplateInstance(component):
> if isinstance(component.parent, VisionTemplate):
> return component.parent
> else:
> templateInstance = getTemplateInstance(component.parent)
> if templateInstance is not None:
> return templateInstance
> class mouseClickListener(MouseListener):
> def mouseClicked(self, event):
> getTemplateInstance(event.source).evaluateCursorAction(event)
> 	
> def mouseEntered(self, event):
> pass
> 	
> def mouseExited(self, event):
> pass
> 	
> def mousePressed(self, event):
> pass
> 	
> def mouseReleased(self, event):
> pass
> 	
> class mouseMovementListener(MouseMotionListener):
> def mouseMoved(self, event):
> getTemplateInstance(event.source).evaluateCursorAction(event)
> 	
> def mouseDragged(self, event):
> pass
> def setListeners(self):
> for component in self.getComponents():
> if component is not None:
> component.addMouseListener(mouseClickListener())
> component.addMouseMotionListener(mouseMovementListener())
> component.setFocusable(True)
> setListeners(component)
> if event.propertyName == 'componentRunning':
> setListeners(event.source)
> 
> ```

I haven't messed with it enough to get it working, but nevertheless, there's the idea if anybody wants to follow it up.

---

_[View the full topic](https://forum.inductiveautomation.com/t/cursor-shape-on-mouse-over/72515)._
