invokeLater in a for loop

Hi,

I’m trying to make a script that runs a db query to retrieve historical data between two dates.
I would like to loop through the result dataset and write each value on a tag, wait 1 second (or more) and write the next value until the end of the dataset.
Any ways to do so ?

Wrap your loop in a function, and call that function with system.util.invokeAsynchronous(). Then you can safely use Thread.sleep() to control your pace. The thread will simply die when your loop exits.

You’ve found one of the rare uses of sleep() that makes sense and won’t break your system.

Thanks alot, this works !
In case it can help hereis my code :

from time import sleep
def wait():
	for row in range(r.getRowCount()):
		val=r.getValueAt(row,1)
		print val
		event.source.parent.getComponent('Numeric Label').value=val
		sleep(3)
startdate=event.source.parent.getComponent('date_start').date
enddate=event.source.parent.getComponent('date_end').date
r=system.db.runPrepQuery("SELECT data FROM table WHERE t_stamp >= ? AND t_stamp<?",[startdate,enddate])
system.util.invokeAsynchronous(wait)
	
	

I’ve put this script on a button in a window. The value is written to a Numeric label with a 3 seconds delay.

Is there any limitation for the sleep function ?
I might use this function with a large amount of data and i wouldn’t want the system to be overload.

This line needs to happen within an invokeLater call or one day your UI might crash/deadlock while running this function.

Despite its generic sounding name, invokeLater is really invoke later on the UI thread, which is required anytime you're manipulating a piece of the UI. Since you've started a new thread with invokeAsync you are no longer on the UI thread and need to get back onto it before manipulating the component.

1 Like

Does the invokeLater call have to be in the wait() function ?

Edit : I changed my script to wrtie the value to a tag :

from time import sleep
def wait():
	for row in range(r.getRowCount()):
		val=r.getValueAt(row,1)
		print val
		def write(val=val):
			system.tag.write("test_replay",val)
		system.util.invokeLater(write)		
        sleep(3)
startdate=event.source.parent.getComponent('date_start').date
enddate=event.source.parent.getComponent('date_end').date
r=system.db.runPrepQuery("SELECT data FROM table WHERE t_stamp >= ? AND t_stamp<?",[startdate,enddate])
system.util.invokeAsynchronous(wait)

It works but is it the right way to do ?

Yes. The sleep must be in the background thread. The interaction with the GUI must be in the foreground, so the background must tell the foreground to write to that property as shown by @Kevin.Herron.

Also, avoid printing in the background. Use a logger instead.

In your OP, you say you would be writing to a tag--that is safe to do in the background without invokeLater().

1 Like

Thanks for your precious help !