Progress Bar showed how to make a progress bar. @abmayfield question in "not responding" vs. "still thinking" prompted me to revisit this. Here's another take, including a cancel button.
not canceled
Cancel button pressed.
progressBarWidth = 500;
progressUpdatesSeconds = 1 / 4; // 1/2 sec updates -> 1300ips, 1/30 -> 1000ips (1/4 compromise speed vs appearance)
cancel = 0; // clear the cancel flag
New Window( "Progressbar demo", //
V List Box( //
cats = Text Box( "" ), // output from the work function
t = Text Box( "", <<setwrap( 500 ) ), // status of the progressbar
H List Box( // Duct tape has a light side and a dark side. So does the progressbar.
left = Spacer Box( size( 0, 10 ), color( "light green" ) ), //
right = Spacer Box( size( progressBarWidth, 10 ), color( "dark green" ) ), //
<<padding( 5, 5, 5, 5 ), // gray wrapper
<<backgroundcolor( "dark gray" ) //
), //
cancelButton = Button Box( "Cancel", cancel = 1 ) // sets the cancel flag
)
);
Wait( 0 ); // allow the window to open, otherwise the updates are not visible
// progressbar variables
startMicroSeconds = HP Time();
workCalls = 0;
recentUpdateMicroSeconds = HP Time();
runSeconds = (recentUpdateMicroSeconds - startMicroSeconds) / 1e6; // so the loop can start
limitSeconds = 10; // time to run the demo
updateProgress = Function( {fractionComplete},
leftsize = Round( progressBarWidth * fractionComplete );
rightsize = progressBarWidth - leftsize;
left << width( leftsize );
right << width( rightsize );
t << settext( Eval Insert( "^workCalls^ iterations in ^char(runSeconds,6,3)^ seconds -> ^workCalls/runSeconds^ ips" ) );
t << updatewindow; // this works without the wait
);
totalCats = 0;
dowork = Function( {},
x = "";
For( i = 1, i <= 1000, i += 1, x = x || "." );
totalCats += 1000;
cats << settext( Eval Insert( "total concatenations=^totalCats^" ) );
);
While( runSeconds < limitSeconds & !cancel, // change this to represent the work you are doing
// do some work, simulated by concatenating strings...
dowork();
// update the progressbar
workCalls += 1;
nowMicroSeconds = HP Time();
// how often does it need to update on the screen?
If( (nowMicroSeconds - recentUpdateMicroSeconds) / 1e6 > progressUpdatesSeconds,
// in this example I'm using a fixed time duration of "limitSeconds" to represent the
// amount of work to be done. And "runSeconds" to represent the amount of work done so far.
// Usually you'll have something other than time: number of rows in a table perhaps, or
// number of categories to make reports for. As long as you know how many total and how
// many completed, you can compute this fraction...
updateProgress( runSeconds / limitSeconds ); // change this to represent the fraction of work finished
recentUpdateMicroSeconds = nowMicroSeconds;
Wait( 0 ); // this wait is needed to let the cancel button work
);
runSeconds = (nowMicroSeconds - startMicroSeconds) / 1e6;
);
If( cancel, // test the cancel flag
Beep(); // audio flag
left << color( "dark red" ); // visual flag something is awry
right << color( "red" );
, //
updateProgress( 1.0 ); // people like to see the bar go to 100%
);
cancelButton << setbuttonname( "Close" ); // visual flag the button function is changed
cancelButton << setscript( (cancelButton << closewindow) ); // and what to do if the button is pressed
Testing between JMP 15 and 16, I noticed 16 is a lot faster on this string concatenation work load! Nice work!
Edit: if JMP is running a platform that does not have its own cancelable progress bar, and it runs for a long time, this is not going to help. Tech Support would be a good place to request the platform support for a progress bar. Without it, there is no way (short of forcibly closing JMP) to stop it until it is done.