The following script works inside a template:
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
:
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
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.