Didacticiel: Widgets listes

Page suivante Page précédente Table des matières

## 9. Widgets listes

Le widget GtkList sert de container vertical pour des widgets GtkListItem.

Un widget GtkList possède sa propre fenêtre pour recevoir les événements et sa propre couleur de fond qui est habituellement blanche. Comme il est directement dérivé de GtkContainer, il peut être traité comme tel en utilisant la macro GTK_CONTAINER(List) : voir le widget GtkContainer pour en savoir plus.

On doit d'abord connaître l'utilisation des GList et des fonctions g_list_*() qui leur sont liées pour pouvoir utiliser pleinement le widget GtkList.

Un champ de la structure d'un widget GtkList nous intéresse particulièrement :

> `

>     struct _GtkList
>     {
>       ...
>       GList *selection;
>       guint selection_mode;
>       ...
>     };

> `

Le champ selection d'un GtkList pointe sur une liste chaînée de tous les items qui sont sélectionnés, ou vaut NULL si aucune sélection n'est faite. Ainsi, pour connaître la sélection courante, on consulte le champ GTK_LIST()->selection mais on ne doit pas le modifier car ses champs internes sont gérés par les fonctions gtk_list_*().

Le champ selection_mode détermine les options de sélection d'un GtkList et donc le contenu du champ du GTK_LIST()->selection :

selection_mode peut avoir l'une des valeurs suivantes :

- GTK_SELECTION_SINGLE - selection vaut NULL ou contient un pointeur vers un seul item sélectionné.
- GTK_SELECTION_BROWSE - selection vaut NULL si la liste ne contient aucun widget ou seulement des widgets non sensitifs. Sinon, ce champ contient un pointeur vers une seule structure Glist, et donc vers exactement un item.
- GTK_SELECTION_MULTIPLE - selection vaut NULL si aucun item n'est sélectionné ou pointe vers le premier item sélectionné. Ce dernier point à son tour vers le second item, etc.
- GTK_SELECTION_EXTENDED - selection vaut toujours NULL.

La valeur par défaut est GTK_SELECTION_MULTIPLE.

## 9.1 Signaux

> `

>     void GtkList::selection_changed (GtkList *LIST)

> `

Ce signal sera invoqué à chaque fois que le champ sélection d'un GtkList a changé. Cela arrive lorsqu'un fils d'un GtkList a été sélectionné ou désélectionné.

> `

>     void GtkList::select_child (GtkList *LIST, GtkWidget *CHILD)

> `

Ce signal est invoqué lorsqu'un fils du GtkList va être sélectionné. Ceci arrive principalement lors d'appels à gtk_list_select_item(), gtk_list_select_child() et lors d'appuis de boutons. Quelques fois, il est indirectement déclenché lorsque des fils sont ajoutés ou supprimés du GtkList.

> `

>     void GtkList::unselect_child (GtkList *LIST, GtkWidget *CHILD)

> `

Ce signal est invoqué lorsqu'un fils du GtkList va être désélectionné. Cela arrive principalement lors d'appels à gtk_list_unselect_item(), gtk_list_unselect_child(), et lors d'appuis de boutons. Quelques fois, il est indirectement déclenché lorsque des fils sont ajoutés ou supprimés du GtkList.

## 9.2 Fonctions

> `

>     guint gtk_list_get_type (void)

> `

Retourne l'identificateur de type « GtkList ».

> `

>     GtkWidget* gtk_list_new (void)

> `

Crée un nouvel objet « GtkList ». Le nouveau widget est retourné sous la forme d'un pointeur vers un objet « GtkWidget ». NULL est retourné en cas d'erreur.

> `

>     void gtk_list_insert_items (GtkList *LIST, GList *ITEMS, gint POSITION)

> `

Insère des items dans LIST, à partir de POSITION. ITEMS est une liste doublement chaînée où chaque noeud doit pointer vers un nouveau GtkListItem. Les noeuds GList de ITEMS sont pris en charge par LIST.

> `

>     void gtk_list_append_items (GtkList *LIST, GList *ITEMS)

> `

Insère des items à la fin de LIST selon le même principe que gtk_list_insert_items. Les noeuds GList de ITEMS sont pris en charge par LIST.

> `

>     void gtk_list_prepend_items (GtkList *LIST, GList *ITEMS)

> `

Insère des items au début de LIST selon le même principe que gtk_list_insert_items. Les noeuds GList de ITEMS sont pris en charge par LIST.

> `

>     void gtk_list_remove_items (GtkList *LIST, GList *ITEMS)

> `

Ôte des items de LIST. ITEMS est une liste doublement chaînée dont chaque noeud pointe vers un fils direct de LIST. Il est de la responsabilité de l'appelant de faire un appel à g_list_free(ITEMS) après cela. L'appelant doit aussi détruire lui-même les items.

> `

>     void gtk_list_clear_items (GtkList *LIST, gint START, gint END)

> `

Ôte et détruit des items de LIST. Un widget est concerné si sa position courante dans LIST est dans l'intervalle spécifié par START et END.

> `

>     void gtk_list_select_item (GtkList *LIST, gint ITEM)

> `

Invoque le signal GtkList::select_child pour un item spécifié par sa position courante dans LIST.

> `

>     void gtk_list_unselect_item (GtkList *LIST, gint ITEM)

> `

Invoque le signal GtkList::unselect_child pour un item spécifié par sa position courante dans LIST.

> `

>     void gtk_list_select_child (GtkList *LIST, GtkWidget *CHILD)

> `

Invoque le signal GtkList::select_child pour le fils CHILD spécifié.

> `

>     void gtk_list_unselect_child (GtkList *LIST, GtkWidget *CHILD)

> `

Invoque le signal GtkList::unselect_child pour le fils CHILD spécifié.

> `

>     gint gtk_list_child_position (GtkList *LIST, GtkWidget *CHILD)

> `

Retourne la position de CHILD dans LIST. Retourne -1 en cas d'erreur.

> `

>     void gtk_list_set_selection_mode (GtkList *LIST, GtkSelectionMode MODE)

> `

Configure LIST dans le mode de sélection MODE qui peut être GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE ou GTK_SELECTION_EXTENDED.

> `

>     GtkList* GTK_LIST (gpointer OBJ)

> `

Convertit un pointeur générique en « <\em GtkList*\ ». Voir Standard Macros::, pour plus d'informations.

> `

>     GtkListClass* GTK_LIST_CLASS (gpointer CLASS)

> `

Convertit un pointeur générique en « GtkListClass* ». Voir Standard Macros::, pour plus d'informations.

> `

>     gint GTK_IS_LIST (gpointer OBJ)

> `

Détermine si un pointeur générique référence un objet « GtkList ». Voir Standard Macros::, pour plus d'informations.

## 9.3 Exemple

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");
>     }

> `

## 9.4 Widget item de liste

Le widget GtkListItem sert de container pour contenir un fils, lui fournissant des fonctions de sélection/déséselection exactement comme le widget GtkList les demande pour ses fils.

Un GtkListItem a sa propre fenêtre pour recevoir les événements et a sa propre couleur de fond, habituellement blanche.

Comme il est directement dérivé d'un GtkItem, il peut être traité comme tel en utilisant la macro GTK_ITEM(ListItem), reportez-vous à la section sur le widget GtkItem pour plus de détail sur celui-ci. Habituellement, un GtkListItem contient juste un label pour identifier, par exemple, un nom de fichier dans un GtkList -- la fonction appropriée gtk_list_item_new_with_label() est donc fournie. Le même effet peut être obtenu en créant un GtkLabel à part, en configurant son alignement avec xalign=0 et yalign=0.5 suivi d'un ajout ultérieur au GtkListItem.

Tout comme on n'est pas forcé d'ajouter un GtkLabel à un GtkListItem, on peut aussi ajouter un GtkVBox ou un GtkArrow etc. à un GtkListItem.

## 9.5 Signaux

Un GtkListItem ne crée pas de nouveaux signaux par lui-même, mais hérite de ceux d'un GtkItem. Voir GtkItem::, pour plus d'informations.

## 9.6 Fonctions

> `

>     guint gtk_list_item_get_type (void)

> `

Retourne l'identificateur du type « GtkListItem ».

> `

>     GtkWidget* gtk_list_item_new (void)

> `

Création d'un objet GtkListItem. Le nouveau widget est retourné sous la forme d'un pointeur vers un objet GtkWidget. NULL est retourné en cas d'erreur.

> `

>     GtkWidget* gtk_list_item_new_with_label (gchar *LABEL)

> `

Création d'un objet GtkListItem ayant un simple GtkLabel comme seul fils. Le nouveau widget est retourné sous la forme d'un pointeur vers un objet GtkWidget. NULL est retourné en cas d'erreur.

> `

>     void gtk_list_item_select (GtkListItem *LIST_ITEM)

> `

Cette fonction est surtout un emballage de gtk_item_select (GTK_ITEM (list_item)) qui émettra le signal GtkItem::select. Voir GtkItem::, pour plus d'informations.

> `

>     void gtk_list_item_deselect (GtkListItem *LIST_ITEM)

> `

Cette fonction est surtout un emballage de gtk_item_deselect (GTK_ITEM (list_item)) qui émettra le signal GtkItem::deselect. Voir GtkItem::, pour plus d'informations.

> `

>     GtkListItem* GTK_LIST_ITEM (gpointer OBJ)

> `

Convertit un pointeur générique en GtkListItem*. Voir Standard Macros:: pour plus d'informations.

> `

>     GtkListItemClass* GTK_LIST_ITEM_CLASS (gpointer CLASS)

> `

Convertit un pointeur générique en GtkListItemClass*. Voir Standard Macros:: pour plus d'informations.

> `

>     gint GTK_IS_LIST_ITEM (gpointer OBJ)

> `

Détermine si un pointeur générique se réfère à un objet GtkListItem. Voir Standard Macros:: pour plus d'informations.

## 9.7 Exemple

L'exemple des GtkList couvre aussi l'utilisation des GtkListItem. Étudiez-le attentivement.

Page suivante Page précédente Table des matières