tags:

views:

56

answers:

2

Hi everyone, 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?

+1  A: 

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()).

mbq
Thank you, I suspected it was something like that, but I wasn't sure how R and GTK were communicating. Do you think calling `Sys.sleep()` is the proper way to force redraw? It seems quite "hacky" to me.
nico
I haven't found anything better yet.
mbq
+3  A: 

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.

hadley