Flow control question: how best to wait for user input from within a loop
I've been struggling with flow control in a program I am developing. Briefly, the user needs to classify some structures in a series of images. I have a master function that gets a list of all the images in a directory and then we will process them using a loop. For each iteration, an image window and panel are shown and the user interacts with them*. What I am struggling with is how to get the loop to wait for user input.
I have tried two things:
1. using return statements to tell the loop that the user has finished. I couldn't get this to work. It seems like my functions that generate the window and panel pop on and off the stack and I can't communicate down to the original loop.
2. using a global variable (a modification of the background task example in the Help). This feels close to working. I set a running variable to 1 and test for 0 status in the loop using do-while. However, it is not possible for the user to interact with the panel is this state (spinning black and white disk).
What am I missing? Is it better to approach this another way? Any help very much appreciated!
* this part works fine and concludes with the user clicking OK in the panel which saves the classification to disk.
I figured a MWE would make it easier to understand my question. Running MWE() redraws the window and panel ten times without waiting for user input.
Ideally I wouldn't use a global variable and would just control everything using return statements. I can't see how to communicate back to the loop in MWE().
Variable i
for(i = 0 ; i < 10; i += 1)
Print "Image", i
MakeWindowAndPanel()
endfor
End
Function MakeWindowAndPanel()
KillWindow/Z myWindow
Display/N=myWindow
FunctionToMakePanel()
End
Function FunctionToMakePanel()
KillWindow/Z myPanel
NewPanel/N=myPanel/K=1/W=(0,0,100,100)/HOST=myWindow/EXT=0
Button Complete,pos={10,40},size={80,20},proc=CompleteButtonProc,title="Complete"
End
Function CompleteButtonProc(ctrlName) : ButtonControl
String ctrlName
strswitch(ctrlName)
case "Complete" :
//Save/J/P=txtDiskFolder/W XW,XW,YW,ktCat as txtName
KillWindow/Z myWindow
KillWindow/Z myPanel
Print "I'm finished"
return 1
endswitch
End
January 3, 2020 at 08:01 am - Permalink
maybe PauseForUser?
I don't find many uses for PauseForUser nowadays, but if I've understood correctly it would seem to fit your task.
Use PauseForUser after building windows to restrict user activity to panel and plot until user clicks on 'Complete'.
January 3, 2020 at 08:15 am - Permalink
Thanks. Ah yes, PauseForUser. I thought this was deprecated, but according to the Help it still works in IP8. I think this might solve my problem.
January 3, 2020 at 08:40 am - Permalink
Not deprecated. I put in a lot of effort to shoehorn that feature into the Igor Qt-based rewrite at Igor 7.
Not deprecated, but not recommended if you can find a different way to write the user interface. It's conceptually easier than writing a control panel, which involves mastering non-sequential programming.
One possible interface would be a listbox showing the available images. Have the user select a line and click a button to commence the analysis of the given image. Disable a selection when it is done.
You could also use a popup menu control and the user would initiate an analysis by selecting an item. Remove items that have been done.
A scheme like that allows a user to take a lunch break without messing up the loop.
January 3, 2020 at 10:21 am - Permalink
Thanks for the input John. I added PauseForUser and it works in preliminary testing, but it feels too precarious. There's a lot of images to process and the user may not want to sit there and work through them all. So I'm going to try your suggestions for alternative interfaces.
January 3, 2020 at 12:57 pm - Permalink
Based on what I am doing in the Image Tools package, I would propose the approach in the attached example experiment.
January 4, 2020 at 08:36 am - Permalink
Thank you. That is nice! For anyone following (or finding) this thread, the idea here is to build the image and panel and then use the complete button to move to the next image in the series. So control is handed to the panel rather than leaving a loop hanging around.
I think I could use this. In my case, the images are large stacks and the user needs to move around with a slider to classify a bunch of features, i.e. I would need to load the images on demand (for memory reasons) and rebuild the window and panel each time. I'm actually almost finished with a version using John's suggestion, but thank you very much for this example.
January 4, 2020 at 12:47 pm - Permalink
I'd be curious to see what you develop as a package.
January 4, 2020 at 01:15 pm - Permalink