Image not responding + if statement query

Can someone tell me why this code isnt causing the image to move? It just doesnt respond at all. Its scripted within propertyChange within the image itself.

I have custom properties set up:

origX - Int
origY - Int
trigger - Bool

all it should be doing is moving the image from its orginal position to those coordinates then back.

component = event.source.parent.getComponent('Image')
origX = component.x
origY = component.y
 
system.gui.transform(
    component,
    93, 466,
    duration=3000,
    callback=lambda: system.gui.transform(
        component,
        origX, origY,
        duration=3000,
        acceleration=system.gui.ACCL_FAST_TO_SLOW
    )
)

the if statement im not sure how to complete properly, I want to set the trigger property to 1 when the component reaches the x coordinate of 93 then set trigger back to 0 when it goes back to its original position. trigger is a property used to fire something else on the screen.


if component.x == 93:
	event.source.trigger = 1 
elif component.x == event.source.origX:
	event.source.trigger = 0

i got it to run, but the image flickers back and forward constantly and never completes the cycle

You need to filter on the property name, otherwise it will trigger on ANY property change.
Something like

if event.propertyName == 'the_property_you_want_to_monitor':
    do_the_thing
3 Likes
  • The thing triggering the transform should be what you filter for.
  • Set up a few functions you can wrap in an invokeLater

Here's a window for you to play with.
test_Transform_2023-11-07_0755.zip (4.4 KB)

Script on the button:

def invoke():
	component = event.source.parent.getComponent('Image')

	def setState(stateIn):
		component.state = stateIn
		
	def setMoveSet(x, y, state1, state2):
		setState(state1)
		system.gui.transform(component, 
							 x, 
							 y, 
							 duration=1000,
							 acceleration=system.gui.ACCL_EASE,
							 callback = lambda state=state2 : setState(state)
							)		
		
	origX = component.x
	origY = component.y
	
	setState(1)	
	system.gui.transform(component, 
						 100, 
						 origY, 
						 duration=1000,
						 acceleration=system.gui.ACCL_EASE,
						 callback = lambda x=origX, y=origY: setMoveSet(x,
						                               y,
						                               2,
						                               0)
						)
						
system.util.invokeLater(invoke)
3 Likes

Hi Jordan, that works beautifully!

why does this work and using transform doesnt? what is invokelater for?

Please correctly assume im an idiot if you manage to describe this and pitch at that level

1 Like

It also uses a transform. The difference is that this is triggered by a button, while you were using a property change script.
The property change script will work, as long as you filter correctly on the property name. What was happening in your attempt is that since the script was triggered by ANY change on ANY property, it was constantly re-triggering and thus resetting positions, which caused the flicker you experienced.
I think.

8 Likes

Pascal is correct on why your script isn't quite working as expected. Using a filter is vital when using a propertyChange script.

invokeLater() is used to run your stuff in a background thread. Running it in the forground will run it in the GUI thread, so nothing in the GUI will update untill it's all over.

Also note that, instead of monitoring when I reached the end of a transform with an 'if' statement, I used a different function in the callback, and used that function to set the state.

If you were to use this in the propertyChange script of the image I would add another custom property (runAnimation, for example) and use that as the filter.

if event.propertyName == 'runAnimation' and event.newValue == True:
	def invoke():
		component = event.source.parent.getComponent('Image')
	
		def setState(stateIn):
			component.state = stateIn
		
		def reset():
			# Reset back to default values and turn off the runAnimation trigger.
			setState(0)
			component.runAnimation = False
			
			
		def setMoveSet(x, y, state1):
			setState(state1)
			system.gui.transform(component, 
								 x, 
								 y, 
								 duration=1000,
								 acceleration=system.gui.ACCL_EASE,
								 callback = lambda : reset()
								)		
			
		origX = component.x
		origY = component.y
		
		setState(1)	
		system.gui.transform(component, 
							 100, 
							 origY, 
							 duration=1000,
							 acceleration=system.gui.ACCL_EASE,
							 callback = lambda x=origX, y=origY: setMoveSet(x,
							                               y,
							                               2)
							)
	#event.source.runAnimation = False					
	system.util.invokeLater(invoke)

1 Like

No, it still runs in the foreground GUI thread.

Only invokeAsynchronous pushes a task to the background, but that isn't appropriate here--you are interacting with components, which is forbidden in the background.

3 Likes

I see this is being done in Vision, is there anyway to do it in Perspective also?

Animation in the web environment works completely differently.

To do something like what's in this post, you "just":

  1. Move the position of an element from somewhere to somewhere else.
  2. Have a CSS animation connected to the element. It will automatically smoothly move the element.
1 Like

LOL, "just".

Interesting. I will do it and report back.

1 Like

Consider starting from the View Canvas component, which does some of the legwork for you:
https://docs.inductiveautomation.com/display/DOC81/Perspective+-+View+Canvas

1 Like

Assuming a coordinate container, add a transition to its styles. Then when you change a css property (such as x and y), it will transition smoothly.
Google "css transition" for the syntax and options.
There are other ways, but I believe this is the easiest and simplest one for a basic animation like this one.

3 Likes