Re: Status for long-running operation



yep, i concur with the set sensitive method.

the way i do this is: when the user:
loop over a list of GtkWidget pointers i have saved to a g_ptr_array() at program startup/widget creation, making them insensitive for the entire duration of the blocking operation.  once the operation completes/returns, execute the set sensitive loop again making all necessary widgets again sensitive, i.e., return to the user access to the widget's function.

you can also use this paradigm to make various widgets visible/invisible, editable/uneditable, or sensitive/insensitive, according to one of many possible display states.  your example has only two states, ON or OFF; however, many other examples abound, e.g., connected/not connected to a DB, viewing data in read-only vs. edit mode, background op is interruptable (making interrupt button the only possible action), etc.

in the example below, the following end-user display states are defined:
  • No connection to DB
  • DB Connection to a particular DB - read-only mode
  • DB Connection to a particular DB - edit mode
  • DB Connection to server - DB Creation mode
for each state, a particular widget is defined to be:
  • sensitive or insensitive
  • visible or invisible
  • editable or non-editable
with this particular model, all states are absolutely defined.  that is, no assumptions are made as to the previous state when setting a widget's current display state.  this is good since you can then just call setDispState() for a particular display state and know that all widgets will be correctly defined and displayed regardless where you're coming from.  as well, as development continues, one need only to add new widgets to the pointer arrays appropriately and everything else just keeps running, no need to write anything further to make a widget's state be what it needs to be.

cheers,

richard


==== BEGIN CODE SNIPPET ==============

enum {         // display states
  DBNOCONN,    // No DB Connection
  DBDISPLAY,   // DB Info Display
  DBEDIT,      // DB Info Edit
  DBCREATE,    // DB Create
  TTLDBDISPSTATES
};

enum {          // display state types
  DISPSENS,     // sensitivity
  DISPVISIBLE,  // visibility
  DISPEDITABLE, // editable
  TTLDISPTYPES
};

enum {          // display state settings
  OFF,
  ON,
  TTLDISPDIRS
};

GPtrArray  *dispState[TTLDBDISPSTATES][TTLDISPTYPES][TTLDISPDIRS];

static void _setSensitive(GtkWidget *widget, gpointer s)
{
  gboolean sens = (gboolean) GPOINTER_TO_INT(s);
  gtk_widget_set_sensitive(widget, sens);
}

static void _setVisible(GtkWidget *widget, gpointer v)
{
  gboolean vis = (gboolean) GPOINTER_TO_INT(v);
  vis ? gtk_widget_show(widget) : gtk_widget_hide(widget);
}

static void _setEditable(GtkWidget *widget, gpointer e)
{
  gboolean edit = (gboolean) GPOINTER_TO_INT(e);
  gtk_editable_set_editable(GTK_EDITABLE(widget), edit);
}

void setDispState(int state)
{  // set all widgets ON | OFF for the requested state
  int i;
  for (i=0;i<TTLDISPDIRS;i++)
  {
    g_ptr_array_foreach(dispState[state][DISPSENS][i], (GFunc) _setSensitive, GINT_TO_POINTER(i));
    g_ptr_array_foreach(dispState[state][DISPVISIBLE][i], (GFunc) _setVisible, GINT_TO_POINTER(i));
    g_ptr_array_foreach(dispState[state][DISPEDITABLE][i], (GFunc) _setEditable, GINT_TO_POINTER(i));
  }
}

void makeWidgets()
{
  int i, j, k;
  // make our display state pointer arrays
  for (i=0;i<TTLDBDISPSTATES;i++)
    for (j=0;j<TTLDISPTYPES;j++)
      for (k=0;k<TTLDISPDIRS;k++)
        dispState[i][j][k] = g_ptr_array_new();

  // A Manage Button that is only displayed when no DB Connection exists, otherwise invisible
  button = gtk_button_new_with_label("Manage");
  g_signal_connect((button), "clicked", G_CALLBACK(servers), NULL);
  g_ptr_array_add(dispState[DBNOCONN][DISPVISIBLE][ON], button);
  g_ptr_array_add(dispState[DBDISPLAY][DISPVISIBLE][OFF], button);
  g_ptr_array_add(dispState[DBEDIT][DISPVISIBLE][OFF], button);
  g_ptr_array_add(dispState[DBCREATE][DISPVISIBLE][OFF], button);
  
  // An Entry Area that is only editable when creating a database, otherwise read-only
  entry = gtk_entry_new();
  gtk_widget_set_tooltip_text(entry, "Name of the Database");
  g_ptr_array_add(dispState[DBNOCONN][DISPEDITABLE][OFF], entry);
  g_ptr_array_add(dispState[DBDISPLAY][DISPEDITABLE][OFF], entry);
  g_ptr_array_add(dispState[DBEDIT][DISPEDITABLE][OFF], entry);
  g_ptr_array_add(dispState[DBCREATE][DISPEDITABLE][ON], entry);

  // A button that is sensitive only when editing a database, otherwise not selectable
  button = gtk_button_new_with_label("ADD");
  g_ptr_array_add(dispState[DBNOCONN][DISPSENS][OFF], button);
  g_ptr_array_add(dispState[DBDISPLAY][DISPSENS][OFF], button);
  g_ptr_array_add(dispState[DBEDIT][DISPSENS][ON], button);
  g_ptr_array_add(dispState[DBCREATE][DISPSENS][ON], button);

  // add all other widgets appropriately as they are created
  //...

  // Initialize Display State to NO DB Connection
  setDispState(DBNOCONN);
}

==== END CODE SNIPPET ==============

On Sat, Sep 18, 2010 at 4:39 AM, Milosz Derezynski <internalerror gmail com> wrote:
One option as already said is a modal dialog with progress bar, another option is to have a progress bar in the main GUI and set the rest of the GUI insensitive (you _really_ should familiarize yourself with gtk_widget_set_sensitive() ).

http://library.gnome.org/devel/gtk/unstable/GtkWidget.html#gtk-widget-set-sensitive

M.


On Sat, Sep 18, 2010 at 3:01 AM, Jeffrey Barish <jeff_barish earthlink net> wrote:
Lex Trotman wrote:

> On 18 September 2010 08:22, Jeffrey Barish <jeff_barish earthlink net>
> wrote:
>> Jeffrey Barish wrote:
>>
>>> My application has one operation that runs for a long time (~1 minute).
>>> During this time, the user is not allowed to do anything.  Nevertheless,
>>> I felt that it was important to give the user some feedback that the
>>> application is still alive and that the operation is running.  My
>>> solution was to print a message in a TextBuffer and follow the message
>>> with a string
>>> of dots that grows in length by one every second.  To get the TextView
>>> to update, I used events_pending/main_iteration.  This all works nicely.
>>> However, because of the events_pending/main_iteration statements, the
>>> entire
>>> GUI is now alive.  Thus, the user is able to do things that disrupt the
>>> long-running operation.  Basically, what I want is a way to get the
>>> TextView to update so that I can update the progress indicator but for
>>> everything
>>> else still to be locked out.  Is there a way to do this?
>>
>> Here's a possibility that seems to work:
>>
>> I used event_handler_set to define an event handler that filters out all
>> events (by not calling main_do_event) except EXPOSE while the
>> long-running operation is underway.  I wish that there were a way to
>> restore the default event handler, but there is only a set method.
>> Anything bad about this solution?
>> --
>> Jeffrey Barish
>
> You should show progress and block the application by showing a modal
> dialog containing a progress bar.
>
> Cheers
> Lex

Good point.  The TextView is where I put all messages, so I didn't want to
put the progress indicator in a different place, if I could avoid it.

My solution still seems to be working, but I worry about having all events
go through my filter all the time because it seems a bit inefficient.
--
Jeffrey Barish

_______________________________________________
gtk-list mailing list
gtk-list gnome org
http://mail.gnome.org/mailman/listinfo/gtk-list



--
Please note that according to the German law on data retention,
information on every electronic information exchange with me is
retained for a period of six months.
[Bitte beachten Sie, dass dem Gesetz zur Vorratsdatenspeicherung zufolge
jeder elektronische Kontakt mit mir sechs Monate lang gespeichert wird.]

_______________________________________________
gtk-list mailing list
gtk-list gnome org
http://mail.gnome.org/mailman/listinfo/gtk-list




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]