Programmation GTK/Exemple

Un livre de Wikilivres.
Programmation GTK
Programmation GTK
Programmation GTK
Sommaire
Modifier ce modèle ce sommaire


Voici un programme affichant les changements de sélection dans une GtkList et permettant d'« emprisonner » des items en les sélectionnant avec le bouton droit de la souris.

 /* Compilez ce programme avec :
  * $ gcc -L/usr/X11R6/lib/ -I/usr/local/include/ -lgtk -lgdk -lglib -lX11 -lm -Wall main.c
  */
 #include        <gtk/gtk.h>
 #include        <stdio.h>
 
 /* Chaîne pour stocker les données dans les items de la liste. */
 
 const   gchar   *list_item_data_key="list_item_data";
 
 
 /* prototypes des gestionnaires de signaux que l'on connectera au widget GtkList. */
 
 static  void    sigh_print_selection    (GtkWidget      *gtklist,
                                          gpointer       func_data);
 static  void    sigh_button_event       (GtkWidget      *gtklist,
                                          GdkEventButton *event,
                                          GtkWidget      *frame);
 
 /* fonction principale pour configurer l'interface utilisateur */
 
 gint main (int argc, gchar *argv[])
 {                                  
     GtkWidget       *separator;
     GtkWidget       *window;
     GtkWidget       *vbox;
     GtkWidget       *scrolled_window;
     GtkWidget       *frame;
     GtkWidget       *gtklist;
     GtkWidget       *button;
     GtkWidget       *list_item;
     GList           *dlist;
     guint           i;
     gchar           buffer[64];
     
     
     /* initialise gtk (et donc gdk) */
 
     gtk_init(&argc, &argv);
     
     
     /* Création d'une fenêtre pour placer tous les widgets.
      * Connexion de  gtk_main_quit() à l'événement "destroy" de
      * la fenêtre afin de prendre en charge les événements « fermeture d'une
      * fenêtre » du gestionnaire de fenêtre. */ 
 
     window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
     gtk_window_set_title(GTK_WINDOW(window), "Exemple de widget GtkList");
     gtk_signal_connect(GTK_OBJECT(window),
                        "destroy",
                        GTK_SIGNAL_FUNC(gtk_main_quit),
                        NULL);
    
    
     /* À l'intérieur de la fenêtre, on a besoin d'une boîte pour placer 
      * verticalement les widgets. */
 
     vbox=gtk_vbox_new(FALSE, 5);
     gtk_container_border_width(GTK_CONTAINER(vbox), 5);
     gtk_container_add(GTK_CONTAINER(window), vbox);
     gtk_widget_show(vbox);
    
     /* Fenêtre à défilement pour placer le widget GtkList à l'intérieur. */
 
     scrolled_window=gtk_scrolled_window_new(NULL, NULL);
     gtk_widget_set_usize(scrolled_window, 250, 150);
     gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
     gtk_widget_show(scrolled_window);
    
     /* Création du widget GtkList
      * Connexion du gestionnaire de signal sigh_print_selection() au signal
      * "selection_changed" du GtkList pour afficher les items sélectionnés
      * à chaque fois que la sélection change. */
 
     gtklist=gtk_list_new();
     gtk_container_add(GTK_CONTAINER(scrolled_window), gtklist);
     gtk_widget_show(gtklist);
     gtk_signal_connect(GTK_OBJECT(gtklist),
                        "selection_changed",
                        GTK_SIGNAL_FUNC(sigh_print_selection),
                        NULL);
     
     /* Création d'une « Prison » pour y mettre un item. */
 
     frame=gtk_frame_new("Prison");
     gtk_widget_set_usize(frame, 200, 50);
     gtk_container_border_width(GTK_CONTAINER(frame), 5);
     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
     gtk_container_add(GTK_CONTAINER(vbox), frame);
     gtk_widget_show(frame);
    
     /* Connexion du gestionnaire de signal sigh_button_event() au signal
      * « mise au arrêts » des items du GtkList. */
 
     gtk_signal_connect(GTK_OBJECT(gtklist),
                        "button_release_event",
                        GTK_SIGNAL_FUNC(sigh_button_event),
                        frame);
    
     /* Création d'un séparateur. */
 
     separator=gtk_hseparator_new();
     gtk_container_add(GTK_CONTAINER(vbox), separator);
     gtk_widget_show(separator);
    
     /* Création d'un bouton et connexion de son signal "clicked" à la
      * destruction de la fenêtre. */
 
     button=gtk_button_new_with_label("Fermeture");
     gtk_container_add(GTK_CONTAINER(vbox), button);
     gtk_widget_show(button);
     gtk_signal_connect_object(GTK_OBJECT(button),
                               "clicked",
                               GTK_SIGNAL_FUNC(gtk_widget_destroy),
                               GTK_OBJECT(window));
    
     /* Création de 5 items, chacun ayant son propre label.
      * Ajout de ceux-ci au GtkList en utilisant gtk_container_add().
      * On interroge le texte du label et on l'associe avec
      * list_item_data_key à chaque item. */
    
     for (i=0; i<5; i++) {
         GtkWidget       *label;
         gchar           *string;
        
         sprintf(buffer, "ListItemContainer avec Label #%d", i);
         label=gtk_label_new(buffer);
         list_item=gtk_list_item_new();
         gtk_container_add(GTK_CONTAINER(list_item), label);
         gtk_widget_show(label);
         gtk_container_add(GTK_CONTAINER(gtklist), list_item);
         gtk_widget_show(list_item);
         gtk_label_get(GTK_LABEL(label), &string);
         gtk_object_set_data(GTK_OBJECT(list_item),
                             list_item_data_key,
                             string);
     }
 
     /* Création de 5 autres labels. Cette fois-ci, on utilise
      * gtk_list_item_new_with_label(). On ne peut interroger la chaîne
      * des labels car on n'a pas les pointeurs de labels et on associe
      * donc simplement le list_item_data_key de chaque item ayant la même 
      * chaîne de texte pour l'ajouter au items que l'on place dans une liste
      * doublement chaînée (GList). On les ajoute alors par un simple appel à
      * gtk_list_append_items().
      * Comme on utilise g_list_prepend() pour mettre les items dans la liste
      * doublement chaînée, leur ordre sera décroissant (au lieu d'être croissant si
      * on utilisait g_list_append()). */
     
     dlist=NULL;
     for (; i<10; i++) {
         sprintf(buffer, "Item avec le label %d", i);
         list_item=gtk_list_item_new_with_label(buffer);
         dlist=g_list_prepend(dlist, list_item);
         gtk_widget_show(list_item);
         gtk_object_set_data(GTK_OBJECT(list_item),
                             list_item_data_key,
                             "Item avec label intégré");
     }
     gtk_list_append_items(GTK_LIST(gtklist), dlist);
    
     /* Enfin, on veut voir la fenêtre... */
    
     gtk_widget_show(window);
    
     /* Lancement de la boucle principale de gtk */
    
     gtk_main();
    
     /* On arrive ici après que gtk_main_quit() ait été appelée lorsque
      * la fenêtre principale a été détruite. */
 
 }
 
 /* Gestionnaire de signal connecté aux événements boutons presser/relâcher
  * du GtkList. */
 
 void
 sigh_button_event       (GtkWidget      *gtklist,
                          GdkEventButton *event,
                          GtkWidget      *frame)
 {
     /* On ne fait quelque chose que si le troisième bouton (celui de droite) a été
      * relâché. */
 
     if (event->type==GDK_BUTTON_RELEASE &&
         event->button==3) {
         GList           *dlist, *free_list;
         GtkWidget       *new_prisoner;
        
         /* On recherche l'item sélectionné à ce moment précis. 
          * Ce sera notre prisonnier ! */
 
         dlist=GTK_LIST(gtklist)->selection;
         if (dlist)
                 new_prisoner=GTK_WIDGET(dlist->data);
         else
                 new_prisoner=NULL;
         
         /* On recherche les items déjà prisonniers et on les
          * remet dans la liste.
          * Il ne faut pas oublier de libérer la liste doublement
          * chaînée que gtk_container_children() retourne. */
        
         dlist=gtk_container_children(GTK_CONTAINER(frame));
         free_list=dlist;
         while (dlist) {
             GtkWidget       *list_item;
            
             list_item=dlist->data;
            
             gtk_widget_reparent(list_item, gtklist);
            
             dlist=dlist->next;
         }
         g_list_free(free_list);
        
         /* Si l'on a un nouveau prisonnier, on l'ôte du GtkList et on le place
          * dans le cadre « Prison ». On doit désélectionner l'item avant.*/
 
         if (new_prisoner) {
             GList   static_dlist;
             
             static_dlist.data=new_prisoner;
             static_dlist.next=NULL;
             static_dlist.prev=NULL;
            
             gtk_list_unselect_child(GTK_LIST(gtklist),
                                     new_prisoner);
             gtk_widget_reparent(new_prisoner, frame);
         }
     }
 }
 
 /* Gestionnaire de signal appelé lorsque le GtkList
  * émet le signal "selection_changed". */
 
 void
 sigh_print_selection    (GtkWidget      *gtklist,
                          gpointer       func_data)
 {
     GList   *dlist;
    
     /* Recherche dans la liste doublement chaînée des items sélectionnés
      * du GtkList, à faire en lecture seulement ! */
 
     dlist=GTK_LIST(gtklist)->selection;
    
     /* S'il n'y a pas d'items sélectionné, il n'y a rien d'autre à faire que
      * de le dire à l'utilisateur. */
 
     if (!dlist) {
         g_print("Sélection nettoyée\n");
         return;
     }
     /* Ok, on a une sélection et on l'affiche. */
 
     g_print("La sélection est ");
    
     /* On récupère l'item dans la liste doublement chaînée 
      * puis on interroge la donnée associée par list_item_data_key
      * et on l'affiche. */
 
     while (dlist) {
         GtkObject       *list_item;
         gchar           *item_data_string;
        
         list_item=GTK_OBJECT(dlist->data);
         item_data_string=gtk_object_get_data(list_item,
                                              list_item_data_key);
         g_print("%s ", item_data_string);
        
         dlist=dlist->next;
     }
     g_print("\n");
 }