I am trying to add a gtkProgressBar
to a little interface I created for an R script (using the RGtk2
package).
If I do something simple, as:
for (i in 1:50)
{
gtkProgressBarSetFraction(progress, i/50)
Sys.sleep(1)
}
everything runs smoothly and the bar is updated every second.
However, when I go to my actual code, I have a loop in which I do something like
for(i in 1:1000)
{
gtkProgressBarSetFraction(progress, i/1000)
#do some heavy computation here
}
The problem here is that the interface "freezes" and the progress bar is only updated at the end of the loop, therefore defeating completely its use...
Am I missing something here? How can I periodically "wake up" the interface so that it refreshes?
Thank you
nico
EDIT: OK, I solved the problem, but I still don't understand what is going on. I added a Sys.sleep
call after the gtkProgressBarSetFraction
and now the interface updates happily. To reduce "wasted time" I just did Sys.sleep(0.0001)
(so for 1000 cycles I would only have ~0.1-1s more computing time, which is acceptable). Anyone could explain why is this happening?
To process one event: gtkMainIterationDo(FALSE)
. To process all pending events: while(gtkEventsPending()) gtkMainIteration()
.
This code is needed because of the way that the R and Gtk event loops interact - at every point, either R or Gtk is in control, and needs to manually hand off control to the other. Sys.sleep
is one way of doing that, and these RGtk2 specific functions are another.
Almost all GUIs are made using concept called event loop. The program has some queue of messages and is itself infinitely looped in a process of picking new messages from the queue and executing them. The queue is populated by some events received from OS, like key strokes, mouse clicks, resizing windows, etc., and by the messages thrown by the program itself.
It doesn't seem like this, but R also has its own event loop (for graphics, but not only, and it is somewhat extended by RGtk, and while it is generally complicated I won't go into details).
Now when you call gtkProgressBarSetFraction
, the progress bar is not directly updated, but a message requesting redraw is created and pushed to the queue. So, it makes no effect till it will be picked by the event loop iteration, but this won't happen until R will finish execution of your script OR when the loop will be fired exceptionally (by an internal timeout or by some functions, like Sys.sleep()
).