Blocking progress bar

I understand the use of invokeAsynchronous()/invokeLater() to display some sort of progress to the user during a long running operation but without locking up the GUI.
The fact here is, in my case I DO want the GUI to remain unusable while the long task runs, since there’s nothing sensible the user can do before it has finished, so (I believe) it makes sense to run the long running code in foreground; however, I’d still like to display some progress indication so they know something is going on. Is this possible? Is there some trick to periodically refresh the GUI that can be called from my code? This is in Vision.

No UI refresh, no. There’s some old posts on using the glass pane of the application to intercept all user input to prevent interference, but you still need to run your computation in the background.

You could put a progress bar component on the screen that kicks this operation off and periodically update it from the background operation using system.util.invokeLater.

Sure, but that leaves the UI available for the user to mess around, which I don’t want them to do.

Yeah, you’d have to disable everything and prevent navigating away somehow.

If you only need to disable action on a single window then you can add a container that is the same size as the window, make the background color semi-transparent and in the container’s mouseClicked event handler put the script “pass” so that it will handle and effectively ignore and mouse clicks.

Make the container visible before your long process starts and hide it when done.

4 Likes

Here is an example using the glass pane.

from java.awt.event import MouseListener
class MyML(MouseListener):
	def mouseClicked(self,e):
		pass
	def mouseDragged(self,e):
		pass
	def mouseEntered(self,e):
		pass
	def mouseExited(self,e):
		pass
	def mouseMoved(self,e):
		pass
	def mousePressed(self,e):
		pass
	def mouseReleased(self,e):
		pass
	def mouseWheelMoved(self,e):
		pass

ml = MyML()
event.source.appContext.rootPaneContainer.glassPane.addMouseListener(ml)
event.source.appContext.rootPaneContainer.glassPane.visible = True

def doAsync(event=event,ml=ml):
	import time
	i = 0
	pb = system.gui.getParentWindow(event).getComponentForPath("Root Container.Progress Bar")
	
	def updateUI(pb=pb):
		#Put your ui update code here
		pb.value += 1
		
	while pb.value < pb.maximum - 1:
		time.sleep(0.1)
		system.util.invokeLater(updateUI)
		
	def doLater(event=event,ml=ml,pb=pb):
		import time
		event.source.appContext.rootPaneContainer.glassPane.removeMouseListener(ml)
		event.source.appContext.rootPaneContainer.glassPane.visible = False
		pb.value = 0

	system.util.invokeLater(doLater)
system.util.invokeAsynchronous(doAsync)

Put this and a progress bar in the root container of a window, and give it a try. It will need to be adapted to your use case, but should give you a head start.

3 Likes

Thanks, both suggestions work and I like both, although in practice @JGJohnson’s solution looks simpler to me so I’ll probably go with that. Thanks!

The main difference in methods is the method JGJohnson recommended only blocks a single vision window, where as my method blocks everything in the application, including all vision windows, and the menu bars. Depending on your requirements, you may have to use one or the other.

Kyle

3 Likes