GtkFr - Cours Gtk+-2

PyLaBarreDeProgression

PageAccueil :: LesNews :: Telechargement :: Liens :: Forum :: LeChat :: Contact
DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur :: Vous êtes 38.107.191.92
<< La sélection de valeurs numérique PyGtk La sélection des fichiers >>


La barre de progression

1. Présentation

Parfois un programme doit faire de gros calculs, et il est utile d’avertir l’utilisateur sur l'avancement du calcul afin qu’il soit au courant et ne pense pas que le programme est bloqué. Le widget GtkProgressBar permet donc d'afficher la progression d'une opération quelconque.

1.2 Hiérarchie

GObject -> GtkObject -> GtkWidget -> GtkProgress? -> GtkProgressBar

2. Utilisation de base

2.1 Création

Ce widget étant comme tous les autres widgets de GTK+ sa fonction de création est très simple :
GtkWidget* gtk_progress_bar_new(void)

2.2 Modification de la position

Pour fixer la position de la GtkProgressBar, la fonction est :
void gtk_progress_bar_set_fraction(GtkProgressBar *pbar, gdouble fraction);
Le paramètre pbar est la barre de progression et le paramètre fraction est la valeur que l'on veut donner à la barre de progression. Cette valeur doit être comprise entre 0.0 (0%) et 1.0 (100%).
Pour connaître la position de la GtkProgressBar, la fonction est tout simplement :
gdouble gtk_progress_bar_get_fraction(GtkProgressBar *pbar);
La valeur de retour est bien entendu comprise entre 0.0 et 1.0.

2.3 Orientation de la barre de progression

La barre de progression peut être soit verticale, soit horizontale. De plus pour chaque position, l'on peut définir le sens de progression, et tout cela avec cette fonction :
void gtk_progress_bar_set_orientation(GtkProgressBar *pbar, GtkProgressBarOrientation orientation);
Le paramètre orientation peut prendre quatre valeurs possible :

Au contraire pour connaître son sens de progression, il faut utiliser la fonction :
GtkProgressBarOrientation gtk_progress_bar_get_orientation(GtkProgressBar *pbar);

2.4 Programme exemple

Notre premier exemple, très simple, sera fait d'une fenêtre (bien entendu) avec à l'intérieur une barre de progression (qui évoluera de droite à gauche) et un bouton qui permettra de faire avancer la barre de progression de 10%. Et lorsque la barre de progression sera à 100%, nous la réinitialiserons à 0%.
#include <stdlib.h>
#include <gtk/gtk.h>

void OnButton(GtkWidget *pWidget, gpointer data);

int main(int argc,char **argv)
{
   GtkWidget* pWindow;
   GtkWidget *pMainVBox;
   GtkWidget *pProgress;
   GtkWidget *pButton;

   gtk_init(&argc,&argv);

   pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   gtk_window_set_title(GTK_WINDOW(pWindow), "GtkProgressBar");
   gtk_window_set_default_size(GTK_WINDOW(pWindow), 320, 200);
   gtk_container_set_border_width(GTK_CONTAINER(pWindow), 4);

   pMainVBox = gtk_vbox_new(TRUE, 0);
   gtk_container_add(GTK_CONTAINER(pWindow), pMainVBox);

   /* Creation de la barre de progression */
   pProgress = gtk_progress_bar_new();
   gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pProgress), GTK_PROGRESS_RIGHT_TO_LEFT);
   gtk_box_pack_start(GTK_BOX(pMainVBox), pProgress, TRUE, FALSE, 0);

   pButton = gtk_button_new_with_label("Ajouter 10%");
   gtk_box_pack_start(GTK_BOX(pMainVBox), pButton, TRUE, FALSE, 0);
   g_signal_connect_swapped(G_OBJECT(pButton), "clicked", G_CALLBACK(OnButton), pProgress);

   gtk_widget_show_all(pWindow);

   g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);

   gtk_main();

   return EXIT_SUCCESS;
}

void OnButton(GtkWidget *pWidget, gpointer data)
{
   gdouble dFraction;

   /* Recuperation de la valeur de la barre de progression */
   dFraction = gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(pWidget));

   dFraction += 0.1;

   if(dFraction > 1.0)
      dFraction = 0.0;

   /* Modification de la valeur de la barre de progression */
   gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pWidget), dFraction);
}
Résultat

3. Utilisation dans une boucle

3.1 Problème

Si nous modifions légèrement le programme précédent pour insérer une boucle qui fera avancer automatiquement la barre de progression (par exemple une boucle de 2000 itérations) cela ne fonctionnera pas. La seule raison pour laquelle cela ne fonctionnera pas est que GTK+ ne reprend pas la main car le programme reste dans la boucle for alors GTK+ ne peut pas mettre à jour les widgets affichés.

3.2 Solution

La solution, est de dire clairement à GTK+ qu’il doit remettre à jour grâce à la fonction suivante :
gboolean gtk_main_iteration (void);
Cette fonction permet de faire, comme son nom l'indique, une seule itération. Donc à ce moment là GTK+ va reprendre la main puis la rendre aussitôt, si bien qu’il pourra mettre à jour les widgets. Il suffit donc d’ajouter cette fonction après gtk_progress_bar_set_fraction pour faire fonctionner correctement notre programme.

Ce problème étant réglé, nous allons faire face à un deuxième problème, ou plutôt pseudo-problème. En général, lorsque le programme fait un gros calcul, l’application doit être "bloquer" pendant ce temps. Donc tant que le traitement n’est pas fini, il faut éviter que l’utilisateur ne puisse change des données. Prenons le cas d’un correcteur d’orthographe, disons qu’il le fasse automatiquement. Pendant qu’il vérifie l’orthographe il serai bête que l’utilisateur puisse modifier le texte, ce qui fausserai alors toute la correction. Pourquoi cet exemple? Et bien le fait de rendre la main a GTK+ lui donne le pouvoir de traiter d’autres évènements, comme un clic de sourie et autres. Donc à tout moment pendant ce calcul l’utilisateur peut modifier quelque chose (ici pas grand choses si ce n’est que re-cliquer sur le bouton de démarrage de la boucle), donc il faut pouvoir l’empêcher de faire une quelconque action.

Nous allons pouvoir bloquer l'utilisateur à l'aide de ces deux fonctions :
void gtk_grab_add (GtkWidget *widget);
void gtk_grab_remove (GtkWidget *widget);
Nous allons faire une description rapide des ces deux fonctions à l'aide d'un exemple. Prenons le cas ou l'utilisateur fait dans une application (de dessin par exemple) une sélection par glissement, quand il quitte la zone pour atterrir à coté voir en dehors de la fenêtre, la sélection continue, et bien c’est parce que l’application se focalise sur la fenêtre de sélection, c’est un peut ce que fait gtk_grab_add. Nous lui donnons un widget et seuls les évènements de ce widget seront traiter par GTK+, et cela tant que gtk_grab_remove n’a pas été invoqué. Si bien que quand l'utilisateur fait une sélection et qu'il passe au-dessus d’un autre widget, il est ignorer.

Voilà maintenant nous avons tout pour que pendant la boucle la barre de progression soit remise à jour et sans que l’utilisateur ne puisse cliquer ailleurs.

3.3 Programme exemple

Nous réutilisons donc l'exemple précédant en modifiant la fonction du bouton qui sert maintenant à démarrer la progression de la barre qui sera effectuer dans la fonction callback.
#include <stdlib.h>
#include <gtk/gtk.h>

void OnButton(GtkWidget *pWidget, gpointer data);

int main(int argc,char **argv)
{
   GtkWidget* pWindow;
   GtkWidget *pMainVBox;
   GtkWidget *pProgress;
   GtkWidget *pButton;

   gtk_init(&argc,&argv);

   pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   gtk_window_set_title(GTK_WINDOW(pWindow), "GtkProgressBar");
   gtk_window_set_default_size(GTK_WINDOW(pWindow), 320, 200);
   gtk_container_set_border_width(GTK_CONTAINER(pWindow), 4);

   pMainVBox = gtk_vbox_new(TRUE, 0);
   gtk_container_add(GTK_CONTAINER(pWindow), pMainVBox);

   /* Creation de la barre de progression */
   pProgress = gtk_progress_bar_new();
   gtk_box_pack_start(GTK_BOX(pMainVBox), pProgress, TRUE, FALSE, 0);

   pButton = gtk_button_new_from_stock(GTK_STOCK_REFRESH);
   gtk_box_pack_start(GTK_BOX(pMainVBox), pButton, TRUE, FALSE, 0);
   g_signal_connect_swapped(G_OBJECT(pButton), "clicked", G_CALLBACK(OnButton), pProgress);

   gtk_widget_show_all(pWindow);

   g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);

   gtk_main();

   return EXIT_SUCCESS;
}

void OnButton(GtkWidget *pWidget, gpointer data)
{
   gdouble dFraction;
   gint i;
   gint iTotal = 2000;

   /* Initialisation */
   gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pWidget), 0.0);

   /* Ici on grab sur la barre de progression pour 2 raisons : */
   /* - cela evite a GTK+ de regarder tous les evenements ce qui rend plus rapide */
   /* l'utilisation de gtk_main_iteration() */
   /* - on empeche toute action de l'utilisateur */
   gtk_grab_add(pWidget);

   for(i = 0 ; i < iTotal ; ++i)
   {
      dFraction = (gdouble)i / (gdouble)iTotal;

      /* Modification de la valeur de la barre de progression */
      gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pWidget), dFraction);

      /* On donne la main a GTK+ */
      gtk_main_iteration ();
   }

   /* On supprime le grab sur la barre de progression */
   gtk_grab_remove(pWidget);
}
Résultat



<< La sélection de valeurs numérique PyGtk La sélection des fichiers >>

Il n'y a pas de commentaire sur cette page. [Afficher commentaires/formulaire]
Apinc