I’ve got a script I am experimenting with that can take a lot of time to execute, so I now use the system.util.invokeAsynchronous to run the script in a separate thread to keep the GUI from locking up. I am using the asynchronous thread to copy files from one place to another, and I would like to show the progress of the file copy with a progress bar. How would I go about this?
I am importing a few python libraries to do this.
Since this sort of thing pops up often, I created a set of wrappers that simplify this stuff, and allows you to directly use functions in your script modules. The wrappers take care of stuffing the arguments you supply into a temporary fuction’s default argument.
For your case, try assignLater(). Nick’s example becomes:
# In a script module in your project:
import shutil
def fileTransfer(label):
path = system.file.openFile()
newPath = "F:\NewFolder"
shutil.copy2(path, newPath)
shared.assignLater(label, "text", "Step one done")
# In your button event
label = event.source.parent.getComponent("Label")
shared.later.callAsync(project.module.fileTransfer, label)
jython2/python2 doesn’t have await. Asyncio and general threading don’t play well together. When it becomes availably in jython (if it ever gets to 3.x), don’t be surprised to find it forbidden in any foreground thread.
def asyncInvoked():
def laterInvoked():
system.gui.messageBox("Please press OK")
system.util.invokeLater(laterInvoked).await()
# Do more stuff after Ok is pressed.
system.util.invokeAsynchronous(asyncInvoked)
Coroutines run in the same thread they are called from, so even if asyncio was available, you aren’t going to be able to await in a background thread for a coroutine to run in a gui thread.
If you absolutely have to pass something back from the UI thread, supply a future for the GUI thread to complete and the async thread to .get().
OK. I’ve poked myself with the futures idea. Grab the latest version of later.py, then try this:
def asyncInvoked():
# do something in the background
shared.later.callLater(system.gui.messageBox, "Please Press OK").get()
# do something after OK is pressed
system.util.invokeAsynchronous(asyncInvoked)
Note the use of .get() to wait for system.gui.messageBox to complete.
This updated later.py includes an emulation of invokeLater for gateway scope. Untested and unsupported!
Edit: Realized the invokeLater emulation should only use one thread. Fixed.
The callLater function works great. There is just a minor bug when a Python exception is thrown.
I made the following workaround (and for all the other functions in the later.py file aswell), don’t know if you can come up with something better.
The linked version of later.py has been updated to wrap python exceptions to (mostly) retain their traceback when captured by the utility functions and delivered to a future.
I apologize for my gross ignorance of this topic. I am self-taught in Python due to Ignition. What should I do with later.py?
I have downloaded it (from the Automation Pros website), created a script called “later” in the shared script library and copied and pasted the contents of later.py into it. Two things are confusing me:
Phil’s comment of “refresh your cache”. This implies (to me at least) that later.py is NOT just a shared script in the script library since presumably any changes to it would be available as soon as I hit the commit button.
The syntax of Phil’s earlier post:
# In a script module in your project:
import shutil
def fileTransfer(label):
path = system.file.openFile()
newPath = "F:\NewFolder"
shutil.copy2(path, newPath)
shared.assignLater(label, "text", "Step one done")
# In your button event
label = event.source.parent.getComponent("Label")
shared.later.callAsync(project.module.fileTransfer, label)
I would have thought that the syntax would be:
shared.later.assignLater(label, "text", "Step one done")
Ah. The comment about system.file.openFile() makes sense. So the example should read something more like this?
# In a script module in your project:
import shutil
path = system.file.openFile()
def fileTransfer(label,path):
newPath = "F:\NewFolder"
shutil.copy2(path, newPath)
shared.later.assignLater(label, "text", "Step one done")
# In your button event
label = event.source.parent.getComponent("Label")
shared.later.callAsync(project.module.fileTransfer, label,path)
Just in case any of my fellow noobs need something to copy and paste.