cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Choose Language Hide Translation Bar
nikles
Level VI

Question on creating progress bars

Hi all.  I have created a window with a progress bar and a "Cancel" button in it.  The intent is to allow the user to stop program execution.  I'm getting an error when I press cancel though, and do not know how to resolve it.  A simplified version of my script is below.  

 

Names Default to Here(1);

//Define progress window
pwin = NewWindow("Progress",
	SB_L = SpacerBox(Size(0, 15), Color("Green")),
	ButtonBox("Cancel", 
		pwin << Close Window;
		Stop();
	)
);

//Sample Loop
For(i=1, i<=10, i++,
	SB_L << Size(i*10, 15);		//update the progress bar
	Wait(1);					//rest of loop
	
);

If I press Cancel while the loop is running, I get the following error:

 

deleted object reference: SB_L << Size(i * 10, 15) in access or evaluation of 'Glue' , pwin = New Window("Progress",
	SB_L = Spacer Box(Size(0, 15), Color("Green")),
	Button Box("Cancel",
		pwin << Close Window;
		Stop();
	)
); /*###*/For(i = 1, i <= 10, i++,
	SB_L << Size(i * 10, 15);
	Wait(1);
) /*###*/;

When the cancel button is pressed, my expectation is that the progress window should close, and then execution should stop.  But it appears to continue on for at least one iteration, and fails at the SB_L << Size() line in the For loop.  It fails because the progress window has closed and SB_L has been deleted, but I'm confused why this line is getting executed if the Stop() command was issued?

 

Am I correct that program execution is continuing even after my Stop() command?  How can I prevent the execution of the SB_L << Size() command after the Cancel button has been pressed?

 

Details:

JMP Pro 15.2.1

Mac OS Big Sur v11.6

 

Thanks.

 

7 REPLIES 7
Ryan_Gilmore
Community Manager Community Manager

Re: Question on creating progress bars

Hi @nikles . You may want to check out this recent post from @Craige_Hales , Progress Bar with Cancel Button .

nikles
Level VI

Re: Question on creating progress bars

Thanks Ryan (and Craige).  This was one option I'm definitely considering, but it requires sending a flag to an if clause in the main script body.  My wish is to just stop program execution using the Stop() command in the Cancel button.  Maybe I can reframe my question: why doesn't my Stop() command seem to stop execution?

nikles
Level VI

Re: Question on creating progress bars

Just noticed something else interesting.  If I comment out the "pwin << Close Window()" command in the Cancel button script, the cancel button no longer stops execution.  It seems the Stop() command is not able to stop the For Loop when it is executed from a button.  Cancel button was able to stop execution before only because removing the window created an error.  

Craige_Hales
Super User

Re: Question on creating progress bars

wait( n ) is a necessary evil in JMP, to be avoided where possible. During a wait, the script that calls wait is paused while the OS can do things, like recognizing a click or making an open window visible. Weird things can happen, because you can use the click to start another script (your example) that touches the environment of the first script. In your example, stop() is stopping the second script. It can also set a global flag. If your project is big enough to worry about keeping track of global variables, you can also use name spaces.

So what is the weird thing that can happen? Mostly windows being closed, or displayboxes being deleted. In particular, imagine a click function that has a script that uses wait(1), and you click the button again, half a second later. A second copy of the script is running inside the first. The original wait(1) won't return until the second script finishes. If the second script closes the window the button lives in, what environment is around the original script? (not the same one as before the wait!) Don't build scripts that require wait without a good reason; most of the time displaybox<<updatewindow or datatable<<runformulas is a better choice.

Craige
nikles
Level VI

Re: Question on creating progress bars

Hi Craige!  Thanks.  Just to clarify, the "Wait(1)" that I added was only to mimic execution of a longer set of commands for this demo, and to give myself enough time to click "Cancel" so I could reproduce the problem.  Did not intend for the Wait to be a necessary part of the script though.

 

If I could attempt to summarize what I believe you're saying:

The Cancel button calls script B that is independent of script A (the main script containing the For Loop).  The Stop command in the script B is able to stop execution of script B, but cannot/will not affect script A.  

Do I have that correct, more/less?  

Craige_Hales
Super User

Re: Question on creating progress bars

Yes. The button script runs in its own "context"; it has no idea there is another script running a wait statement. They can communicate via globals. And to finish the weird possibilities, using a wait in a button script also means you can click the close X on the window running the script... when the wait finishes, jmp tries to stop the script safely. Usually the next statement after the wait will not be executed if the window holding the button script is closed during the wait.

Edit: also, the wait is needed to process the click on the cancel button. 

Craige
ErraticAttack
Level VI

Re: Question on creating progress bars

Unfortunately you cannot do what you want here without doing what is essentially a bad-practice hack.  JMP scripts are single threaded, and a progress bar with a cancel button mostly only makes sense in a multi-threaded system where you've got the GUI / Event Loop on the main thread and all scripts and function calls on worker threads.

 

Even in these cases though you'd need some sort of sentinel to properly handle cancels and such.  It certainly would be possible to have a cancel button kill threads, but in general you need a safe stop path -- some sort of abort branch.

 

You can do this in JSL, but it requires either Wait( ... ) statements or <<Update Window() statements, both of which have potentially severe consequences.  Notably, you can have code that is unintentionally executed during the Event Loop that can mangle variable names within your script -- this can happen, as an example, if a graphics script exists on a graph and is executed (JMP extremely aggressively executes graphics scripts), and these scripts can exist on a users system from other addins beyond your control.  It certainly is best to never give execution back to the Event Loop until your script has finished (and obviously to keep the script as short as possible to avoid JMP appearing frozen).  Long and short of it is -- do not give execution back to the Event Loop.

 

I personally find it a bit shortsighted of the JMP team to not have a multi-threaded execution paradigm within JSL at this point (it's almost 2022!), but it is what it is.

 

One thing to note -- you can run external programs and talk to them via IPC through STDOUT.  You can, for example, use Python to do some sort of long-running work and use STDOUT to know when it's finished (and even start a JMP script on some sort of STDOUT sentinel).

Jordan