programmer
programmer

Reputation: 1094

GTK# ProgressBar not updating until process is finished (and I have tried Application.Invoke())

I'm new to GTK# (and desktop development in general). I have set up a small app in MonoDevelop with just a progress bar and a button to test it. The thing is it is not updating until my fake process is finished. I have seen other posts saying that Application.Invoke() is needed according to this link Mono Best Practices. But I still can't get this thing to work, it's probably a fundamental flaw in my understanding. Here is my code:

using System;
using Gtk;
using System.Diagnostics;
using System.Threading;

public partial class MainWindow: Gtk.Window
{   
    public MainWindow (): base (Gtk.WindowType.Toplevel)
    {
        Build ();
    }

    protected void OnDeleteEvent (object sender, DeleteEventArgs a)
    {
        Application.Quit ();
        a.RetVal = true;
    }

    protected void OnOkClicked (object sender, EventArgs e)
    {
        for (int i = 0; i < 100; i++){
            Thread.Sleep(1000);
            Application.Invoke (delegate {
                progressbar1.Fraction = i / 100.0;
            });
        }
    }
}

Upvotes: 2

Views: 1819

Answers (2)

OM55
OM55

Reputation: 1058

What probably happens is that the event (signals) that take care of the visual update of the progress bar are lower in priority, so although they are sent, the progress bar visual display does not get updated but only at the end of the critical section in the code.

You can bypass that also by forcing the signals to be processed. For example:

progressbar1.GdkWindow.ProcessUpdates (true); // Request visual update
while(Application.EventsPending()) Application.RunIteration(true); // Process any messages waiting in the Application Message Loop

Hope that helps.

Upvotes: 3

programmer
programmer

Reputation: 1094

I found an example on Application.Invoke at Mono Responsive Applications which helped me figure out what I needed to do. Here is the updated version of my code:

using System;
using Gtk;
using System.Threading;

public partial class MainWindow: Gtk.Window
{   
    public MainWindow (): base (Gtk.WindowType.Toplevel)
    {
        Build ();
    }

    protected void OnDeleteEvent (object sender, DeleteEventArgs a)
    {
        Application.Quit ();
        a.RetVal = true;
    }

    protected void OnOkClicked (object sender, EventArgs e)
    {
        Thread thr = new Thread (new ThreadStart (ThreadRoutine));
        thr.Start ();
    }

    void ThreadRoutine ()
    {
        for (int i = 0; i < 100; i++)
        {
            LargeComputation ();
            Application.Invoke (delegate {
                progressbar1.Fraction = i / 100.0;
            });
        }
    }

    void LargeComputation ()
    {
        // lots of processing here
        Thread.Sleep(1000);
    }
}

Upvotes: 0

Related Questions