Synching Task and the relative GUI

Hi all,
I am having some issues in synching a task and its relative GUI.

My goal is to have a progress bar that shows the progress of the process I start with a button. I thought the LevelIndicator could have been useful for that purpose, so I went for it. The problem I am experiencing is that, when the .do cycle in the Task starts, all the subsequent -defer seem to be put on hold and evaluated all at once only at the very end. I am sure I am missing something related to synching, but I can’t really see it.

The attached code below is not really the one I am working on, but just a reduced one to reproduce the issue.

(
var textEntry, button, logWindow, progressBar, progressBarVal = 0;
var task, data = 1e7;

// TASK
(
task = Task({
	1.do({
		0.5.wait;
		{logWindow.setString("New analysis started... \n")}.defer;
		"New analysis started...".postln;
		// ... some analysis
		3.wait;
		{logWindow.setString("FFT analysis done.\n")}.defer;
		"FFT analysis done.".postln;
		(
			{logWindow.setString ("Saving to file...\n")}.defer;
			"Saving to file...".postln;
			// This will save all the data in a csv file
			data.do({ |value, index|
                // ... something done on the data ...
				if(index%1e5==0,
					{
						progressBarVal = round(index/data, 0.01);
						progressBarVal.postln;
						{progressBar.value_(progressBarVal)}.defer;
				});
			});
			{logWindow.setString("Saving file done.\n")}.defer;
			"Saving file done.".postln;
		);
		1.wait;
		{logWindow.setString("Searching completed.\n")}.defer;
		"Searching completed.".postln;
		{button.value = 2}.defer;
	});
});
);

// GUI
(
w = Window("Test", Rect(450, 200, 700, 300)).front.background_(Color.new255(211, 210, 190));

z = w.addFlowLayout;
//
button = Button(w, 350 @ 50).font_(Font("Helvetica", 20));
button.states = [["Start analysis", Color.black, Color.green],["Analyzing...", Color.black, Color.red],["Analysis completed", Color.black, Color.green]];
z.nextLine;
//
progressBar = LevelIndicator(w, 700@35);
progressBar.meterColor_(Color.green).warningColor_(Color.green).criticalColor_(Color.green);
z.nextLine;
//
logWindow = TextView(w.asView, Rect(10, 10, 600, 100));
logWindow.editable = false;
logWindow.hasVerticalScroller_(true);
//
button.action = {|view|
	if (view.value == 1) {
		task.start;
	};
};
)
)

Cheers,
Claudio

For a GUI to update, it’s necessary for the interpreter to give up control momentarily – in a Task, this means .wait. The wait time can be very small but shouldn’t be 0 IIRC.

hjh

Thanks!
I tried adding a 0.01.wait

{
		data.do({ |value, index|
				if(index%1e4==0,
					{
						progressBarVal = round(index/data, 0.01);
						progressBarVal.postln;
						{progressBar.value_(progressBarVal)}.defer;
						0.01.wait;
				});
			});

but doesn’t seem to work. It works instead with 0.1.wait, which makes me suspect that the higher will be the value of data, the higher will be the time wait required. This will then add quite a lot of extra time in the overall process.
In general, my data will be a FloatArray with typically data.size>1e7. Should I maybe just change approach and detach the progress bar from the .do cycle?

You could have a separate thread that polls the index value every 0.1 seconds (or whatever update rate you need) and updates the progress bar accordingly.

Something like:

fork {
    {
        progressBar.value = index / data.size();
    }.defer();
    0.1.wait();
}