You are on page 1of 41

LES LISTES ET ARBRES EN GTK+

Par : Jean-Robert SCHLOSSER http://jeanrobert.schlosser.free.fr

GInterface +----GtkTreeModel +----GtkTreeSortable +----GtkCellEditable GObject +----GtkTreeStore +----GtkListStore +----GtkTreeModelSort +----GtkTreeSelection +----GtkObject +----GtkTreeViewColumn +----GtkWidget | +----GtkContainer | +----GtkTreeView +----GtkCellRenderer +----GtkCellRendererPixbuf +----GtkCellRendererText +----GtkCellRendererToggle

Version : 0.5 Date : 24 fvrier 2004 13h45

Les listes et arbres en GTK+

COPYRIGHT
Copyright 2004 Jean-Robert SCHLOSSER Vous avez la permission de copier et de distribuer ce document sans y apporter de de modification. Vous avez aussi la possibilit de modifier ce document condition de garder intgralement cette mention de copyright ainsi que le nom de l'auteur et de fournir un accs direct au document original. You have permission to copy and distribute this document without any modification You have also permission under the condition that you keep integrally this mention of copyright and the author's name, and give a direct access to the original document.

2004 Jean-Robert SCHLOSSER

2 / 41

Les listes et arbres en GTK+

Table des matires


Prsentation................................................................................................................................ 5 Principes de base....................................................................................................................... 6
Les concepts........................................................................................................................................... 6 Le stockage des donnes....................................................................................................................... 6 La prsentation en liste et en arbre........................................................................................................ 8 La slection............................................................................................................................................. 9

La gestion des magasins en dtail.......................................................................................... 11


Les accs aux donnes (lignes / enregistrements).............................................................................. 11 Les conversions............................................................................................................................... 11 Les traitements des itrateurs.......................................................................................................... 11 Les traitements des chemins........................................................................................................... 12 Les traitements des rfrences........................................................................................................13 La cration des lignes........................................................................................................................... 13 Le tri des lignes..................................................................................................................................... 14 Les lments de base pour les tris.................................................................................................. 14 Le tri dans le magasin...................................................................................................................... 15 Le tri par les titres de colonne.......................................................................................................... 15 Le magasin tri intermdiaire........................................................................................................... 16 La technique...................................................................................................................................... 16 Remarque sur les itrateurs et les chemins...................................................................................... 16 Les signaux...................................................................................................................................... 17 Les changements dans l'ordre des lignes............................................................................................ 18 Le parcours du magasin....................................................................................................................... 19 Parcours global avec la fonction de rappel...................................................................................... 19 En grant la boucle d'itration..........................................................................................................20

La gestion de l'affichage en dtail.......................................................................................... 22


L'afficheur............................................................................................................................................. 22 Les liens avec le magasin................................................................................................................ 22 La configuration de l'afficheur.......................................................................................................... 22 Masquer les titres de colonnes.......................................................................................................... 22 Autoriser le click sur les titres de colonne......................................................................................... 22 Gestion des marques de suivi des lignes.......................................................................................... 22 Gestion des regroupements de lignes............................................................................................... 23 La gestion des colonnes.................................................................................................................. 23 La fonctionnalit de recherche interactive........................................................................................24 L'ajout d'ascenseurs.........................................................................................................................24 La colonne............................................................................................................................................ 25 La gestion des afficheurs lmentaires........................................................................................... 25 Visibilit et redimensionnement........................................................................................................26 Visibilit d'une colonne...................................................................................................................... 26 Redimensionnement de la largeur d'une colonne............................................................................. 26 Autres attributs de la colonne...........................................................................................................28 Gestion du titre de la colonne............................................................................................................ 28 La cellule............................................................................................................................................... 28 La gestion des attributs.................................................................................................................... 28 La notion d'attribut............................................................................................................................. 28 Les attributs variables....................................................................................................................... 29 Les attributs constants...................................................................................................................... 29 Les 3 types d'afficheurs lmentaires.............................................................................................. 29 Afficheur de texte.............................................................................................................................. 29 Afficheur d'icne................................................................................................................................ 29 Afficheur binaire................................................................................................................................ 30 Fonction d'affichage spcifique........................................................................................................ 30 dition sur place ............................................................................................................................. 31
2004 Jean-Robert SCHLOSSER 3 / 41

Les listes et arbres en GTK+

Afficheur de texte............................................................................................................................. 31 Afficheur d'icne............................................................................................................................... 32 Afficheur binaire............................................................................................................................... 32 Informations diverses............................................................................................................................32 Double-click sur une colonne........................................................................................................... 32 Gestion d'un menu contextuel.......................................................................................................... 33

La gestion des slections en dtail......................................................................................... 34


Rcuprer les lments slectionns................................................................................................... 34 Rcuprer une slection unique...................................................................................................... 34 Rcuprer la liste des lments slectionns..................................................................................34 Fonction de rcupration d'une slection.......................................................................................... 34 Transformation des chemins en rfrences...................................................................................... 34 Parcours de la liste............................................................................................................................ 34 Libration de la mmoire................................................................................................................... 35 Parcourir la liste des lments slectionns.................................................................................... 35 Changement de la slection................................................................................................................. 36 Changer la slection par programme...............................................................................................36 Grer le changement de slection................................................................................................... 36

Trucs et astuces divers............................................................................................................ 37


Remonter de la colonne d'un afficheur la colonne d'un magasin...................................................... 37 La mthode complte.......................................................................................................................37 Une astuce pour s'en sortir.............................................................................................................. 37 Choisir entre colonne et afficheur lmentaire.................................................................................. 37 Associer le numro de colonne......................................................................................................... 37

Annexes..................................................................................................................................... 39
Dfinitions des constantes.................................................................................................................... 39 Types de colonne............................................................................................................................. 39 Modes de slection.......................................................................................................................... 39 Attributs des afficheurs lmentaires....................................................................................................39 Afficheur de texte............................................................................................................................. 39 Afficheur d'icne............................................................................................................................... 41 Afficheur boolen............................................................................................................................. 41 Documentation...................................................................................................................................... 41 API officielle......................................................................................................................................41 Autres tutoriels................................................................................................................................. 41 Reste faire..........................................................................................................................................41

2004 Jean-Robert SCHLOSSER

4 / 41

Les listes et arbres en GTK+

Prsentation

PRSENTATION
GTK+ est une bibliothque d'objets graphique qui a t conue au dpart pour faciliter le dveloppement de GIMP (GNU Image Manipulation Program). L'intrt de ce type d'outil s'est vite manifest et d'autres projets l'ont utilis comme GNOME un environnement de travail pour Linux. Depuis sa version 2.0, GTK+ recouvre un empilement de bibliothques apportant des fonctions de plus en plus volues. Glib / Gobject / Pango / ATK / GdkPixbuf / GDK / GTK Comme beaucoup de bibliothques graphiques, GTK+ dfinit des objets widget comme base de son architecture. Parmi les changements importants apports par la version 2.0, les techniques de prsentation des listes, simples ou arborescentes, ont t profondment revues. C'est la prsentation de ces techniques et des widgets associs qui constitue l'objet de ce document. Il s'inscrit naturellement dans un cycle d'apprentissage de l'utilisation de GTK ; il n'est donc pas ncessaire d'tre un spcialiste pour profiter de cette prsentation, mais la connaissance pralable des notions de base d'utilisation de la bibliothque est indispensable. Dans un premier temps, on traite ici d'un dveloppement en langage C. Le document pourra ultrieurement tre complt pour prsenter les notions dans d'autres langages. Cette prsentation se veut rsolument didactique et pdagogique. Elle est donc complte, mais pas exhaustive et elle n'est pas organise comme un manuel de rfrence qu'elle ne saurait remplacer.

2004 Jean-Robert SCHLOSSER

5 / 41

Les listes et arbres en GTK+

Principes de base

PRINCIPES DE BASE
Les concepts
L'ide de base est de sparer l'aspect stockage des donnes de l'aspect prsentation. La partie stockage est prise en charge au travers de GtkTreeModel qui est l'objet gnrique qui se dcline en GtkListStore pour les listes simples et GtkTreeStore pour les listes arborescentes. Il est possible, au prix d'un effort supplmentaire, de crer d'autres types de stockage1. La prsentation quant elle, se dcline en GtkTreeView, GtkTreeViewColumn, GtkCellRenderer. Cela permet d'avoir une gestion fine de l'affichage souhait. Le but des cell renderers est de permettre d'avoir plusieurs faons d'afficher un mme type de donnes. A titre d'exemple, regardons comment afficher une variable boolenne. doit-on l'afficher comme un texte Vrai ou Faux , Oui ou Non , ou doit-on la rendre par une case cocher ? L'intrt majeur d'une telle organisation et qu'elle permet d'avoir plusieurs vues sur un mme ensemble de donnes. Attention malgr tout, les 2 parties ne sont pas indpendantes, et il convient de veiller maintenir la cohrence. Une notion complmentaire de Slection , cheval entre les deux aspects principaux, vient complter cet ensemble pour permettre la manipulation des donnes au travers de l'affichage.

Le stockage des donnes


Nous avons vu qu'il fallait choisir entre deux modles (liste simple ou arborescente) pour le stockage des donnes (magasin). Cependant la cration reste trs simple et homogne grce aux fonctions :
GtkListStore* gtk_list_store_new(gint n_columns, GType *types...); GtkTreeStore* gtk_list_store_new(gint n_columns, GType *types...);

Le premier paramtres donne le nombre de colonnes, tandis que les suivants donnent le type de chacune des colonnes (cf. Types de colonne page 39). Maintenant que nous avons cr le magasin, il faut le remplir avec les donnes. Pour cela, il nous faut un petit accessoire, un itrateur qui s'obtient grce aux fonctions :
void gtk_list_store_append(GtkListStore *list_store, GtkTreeIter *iter); void gtk_tree_store_append(GtkListStore *list_store, GtkTreeIter *iter, GtkTreeIter *iterparent);

Le premier paramtre donne bien videmment le magasin que l'on remplit, tandis que le second donne l'emplacement remplir. Le troisime paramtre qui n'existe que dans le cas de l'arbre permet de grer l'arborescence en indiquant l'itrateur du parent auquel est rattach cet lment. En fait, ces fonctions font plus que nous allouer un itrateur, elles crent une ligne vide et nous rendent un itrateur qui pointe vers la nouvelle ligne. Et pour charger nos donnes, il suffit d'utiliser les fonctions :
void gtk_list_store_set(GtkListStore *list_store, GtkTreeIter *iter, ...); void gtk_tree_store_set(GtkListStore *list_store, GtkTreeIter *iter, ...);

Le premier paramtre donne bien videmment le magasin que l'on remplit, tandis que le second donne l'emplacement remplir.
1 Cet aspect ne sera pas abord ici. 2004 Jean-Robert SCHLOSSER 6 / 41

Les listes et arbres en GTK+

Le stockage des donnes

Les paramtres suivants marchent par couple : numro de colonne et valeur de la colonne. Un dernier paramtre, ne pas oublier, vaut toujours -1 et permet d'indiquer la fin de la liste des couples colonne/valeur. Ces fonctions permettent de remplir un nombre quelconque de colonnes (champs) en une seule fois, il est donc possible de les appeler plusieurs fois de suite, ou de mettre tous les valeurs en une seule fois. Pour remplir la liste par le dbut (haut) plutt que par la fin (bas), il faut utiliser les fonctions gtk_list_store_prepend() et gtk_tree_store_prepend() la place de gtk_list_store_apppend() et gtk_tree_store_apppend(). Pour vider compltement un magasin de donnes, il faut utiliser les fonctions :
void gtk_list_store_clear(GtkListStore *list_store); void gtk_tree_store_clear(GtkTreeStore *tree_store);

Tandis que pour supprimer une ligne dont on connat l'itrateur (par exemple au travers d'une slection, voir plus loin), il faut utiliser les fonctions :
gboolean gtk_list_store_remove(GtkListStore *list_store, GtkTreeIter *iter); gboolean gtk_tree_store_remove(GtkTreeStore *tree_store, GtkTreeIter *iter);

Un exemple vaut mieux qu'un long discours :


/* Liste simple : Livres : Titre, Auteur, Lu (Oui/Non) */ GtkListStore* store; GtkTreeIter iter store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); gtk_list_store_append(store, &iter); gtk_list_store_set (store, &iter, 0, "Un livre", 1, "Matthieu",2 , true, -1); gtk_list_store_append(store, &iter); gtk_list_store_set (store, &iter, 0, "Autre livre", 1, "Pascal",2 , false, -1);

2004 Jean-Robert SCHLOSSER

7 / 41

Les listes et arbres en GTK+

Le stockage des donnes

/* Arbre : Livres : Titre, Auteur, Lu (Oui/Non) */ GtkTreeStore* store; GtkTreeIter iter1, iter2; store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); gtk_tree_store_append(store, &iter1, NULL); gtk_tree_store_set (store, &iter1, 0, "Un livre", 1, "Matthieu",2 , true, -1); gtk_tree_store_append(store, &iter1, NULL); gtk_tree_store_set (store, &iter1, 0, "Autre livre", 1, "Pascal",2 , false, -1); gtk_tree_store_append(store, &iter2, &iter1); gtk_tree_store_set (store, &iter2, 0, "Volume 1", 1, "Pascal",2 , true, -1); gtk_tree_store_append(store, &iter2, &iter1); gtk_tree_store_set (store, &iter2, 0, "Volume 2", 1, "Pascal",2 , false, -1);

La prsentation en liste et en arbre


Il y a un seul afficheur pour les listes et les arbres ; le format s'adapte en fonction des donnes. Il y a trois formateurs de cellule ( cell renderer ) qui font partie de GTK+ 2.0. Un format texte, un format image, et un format case cocher. Il est relativement facile d'en crire d'autres2. La premire tape consiste crer un afficheur et l'associer au magasin de donnes :
GtkWidget* gtk_tree_view_new_with_model(GtkTreeModel *model);

Ensuite, il faut ajouter les colonnes afficher :

premirement, il faut choisir le formateur de cellule appropri :

GtkCellRenderer *gtk_cell_renderer_text_new(); GtkCellRenderer *gtk_cell_renderer_pixbuf_new(); GtkCellRenderer *gtk_cell_renderer_toggle_new();

ensuite, il faut crer la colonne avec ses attributs,


(const gchar *title, GtkCellRenderer *cell, ...);

GtkTreeViewColumn* gtk_tree_view_column_new_with_attributes

Le premier paramtre est le titre de la colonne ; le second est le formateur de cellule choisi prcdemment ; enfin on trouve une liste de couples attribut/valeur termine par un NULL (la valeur est en fait le numro de colonne du magasin qui contient la valeur). enfin, il faut associer la colonne l'afficheur avec :
gint gtk_tree_view_append_column(GtkTreeView *tree_view, GtkTreeViewColumn *column);

Le premier paramtre est l'afficheur, le second la colonne, et la valeur de retour le nombre de colonnes de l'afficheur aprs excution de la fonction.
2 Voir plus loin dans ce document. 2004 Jean-Robert SCHLOSSER 8 / 41

Les listes et arbres en GTK+

La prsentation en liste et en arbre

Il ne reste plus maintenant qu' insrer la vue dans la fentre, comme n'importe quel autre widget. Un exemple vaut mieux qu'un long discours :
/* Affichage de la liste ou de l'arbre */ GtkWidget *tree; GtkCellRenderer *renderer; GtkTreeViewColumn *column; tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes ("Auteur", renderer, "text", 0, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); /* Insertion du widget dans la fentre */ gtk_box_pack_start(GTK_BOX(pHBox), tree, FALSE, TRUE, 0);

Prcisons aussi que l'afficheur de listes et d'arbres fait partie des 3 widgets qui peuvent facilement disposer d'ascenseurs. Il suffit de crer une fentre avec barres de dfilement et d'insrer notre liste dedans. Pour crer la fentre avec barres de dfilement, on utilise :
GtkWidget* gtk_scrolled_window_new(GtkAdjustment *hadjustment, GtkAdjustment *vadjustment);

On peut changer les proprits d'affichage des ascenseurs avec :


void gtk_scrolled_window_set_policy(GtkScrolledWindow *scrolled_window, GtkPolicyType hscrollbar_policy, GtkPolicyType vscrollbar_policy);

Pour les deuxime (ascenseur horizontal) et troisime (ascenseur vertical) paramtres, on utilise les constantes GTK_POLICY_ALWAYS, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC dont la signification est vidente. Un exemple vaut mieux qu'un long discours :
/* Ajout dans la fentre avec des ascenseurs */ GtkWidget *tree, *pScrollbar; pScrollbar = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pScrollbar), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(pScrollbar), tree); gtk_box_pack_start(GTK_BOX(pHBox), pScrollbar, FALSE, TRUE, 0);

La slection
La slection est cheval entre l'affichage sur lequel elle est mise en vidence et les donnes sousjacentes du magasin. Il s'agit donc d'un concept complmentaire, mis en uvre l'aide d'un widget spcifique. La premire tape consiste donc rcuprer l'objet slection de l'afficheur grce la fonction :
GtkTreeSelection* gtk_tree_view_get_selection(GtkTreeView *tree_view);

2004 Jean-Robert SCHLOSSER

9 / 41

Les listes et arbres en GTK+

La slection

Il est ensuite possible de fixer certains attributs de la slection grce la fonction :


void gtk_tree_selection_set_mode(GtkTreeSelection *selection, GtkSelectionMode type);

qui permet de choisir le mode de slection en utilisant les constantes : GTK_SELECTION_NONE, GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE. (cf. Modes de slection page 39) Maintenant, il peut tre intressant de rcuprer la description des donnes slectionnes. Dans le cas o on a choisi un mode de slection simple, il est possible de rcuprer le magasin et l'itrateur de la donnes par la fonction :
gboolean gtk_tree_selection_get_selected (GtkTreeSelection *selection, GtkTreeModel **model, GtkTreeIter *iter);

La fonction retourne une valeur vraie lorsqu'un lment est effectivement slectionn. Dans le cas o l'on utilise un mode de slection multiple, c'est un peu plus compliqu ; les explications sont plus loin dans ce document. Sous rserve de connatre l'itrateur, il est possible de slectionner ou d-slectionner une ligne grce aux fonctions :
void gtk_tree_selection_select_iter (GtkTreeSelection *selection, GtkTreeIter *iter); void gtk_tree_selection_unselect_iter (GtkTreeSelection *selection, GtkTreeIter *iter);

Enfin il est possible d'effacer toute slection grce la fonction :


void gtk_tree_selection_unselect_all(GtkTreeSelection *selection);

Et si la slection est multiple, de tout slectionner par :


void gtk_tree_selection_select_all(GtkTreeSelection *selection);

Un exemple vaut mieux qu'un long discours :


/* Exemple de cration de la slection */ GtkTreeSelection *select; select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)); gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE); /* Exemple dans la fonction de rappel d'un bouton "Supprimer" */ GtkTreeIter iter; GtkListStore *store; if(gtk_tree_selection_get_selected (select, &store, &iter)) gtk_list_store_remove(store, &iter);

2004 Jean-Robert SCHLOSSER

10 / 41

Les listes et arbres en GTK+

La gestion des magasins en dtail

LA GESTION DES MAGASINS EN DTAIL


Les accs aux donnes (lignes / enregistrements)
Il existe plusieurs moyens de dsigner l'emplacement des donnes dans le magasin. Ce sont : les itrateurs, qui constituent la mthode base, les chemins (path), qui permettent une description textuelle de l'arborescence, donc particulirement adapts dans le cas des arbres, un chemin est conceptuellement la liste des numro d'ordre chaque niveau, sous forme de texte, c'est une chane de caractres constitue d'entiers positifs ou nuls spars par des : , les rfrences, qui restent lies aux donnes mme en cas de modification dans le magasin. Il existe de nombreuses fonctions pour manipuler ces entits et les convertir entre elles. Sans tre exhaustif, voici les principales :

Les conversions
Convertir un itrateur en chemin :
GtkTreePath* gtk_tree_model_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter);

La mmoire alloue pour le chemin doit ensuite tre libre par :


void gtk_tree_path_free(GtkTreePath *path);

Et voici une autre fonction qui fait, presque, la mme chose :


gchar *gtk_tree_model_get_string_from_iter (GtkTreeModel *tree_model, GtkTreeIter *iter);

Convertir un chemin en rfrence :


GtkTreeRowReference* gtk_tree_row_reference_new (GtkTreeModel *model, GtkTreePath *path);

Convertir une rfrence en chemin :


GtkTreePath* gtk_tree_row_reference_get_path(GtkTreeRowReference *reference);

renvoie NULL si la rfrence n'est pas valide. Convertir un chemin en itrateur :


gboolean gtk_tree_model_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path);

et, en partant du texte du chemin, on utilise :


gboolean gtk_tree_model_get_iter_from_string (GtkTreeModel *tree_model, GtkTreeIter *iter, const gchar *path_string);

Les traitements des itrateurs


Connatre l'enregistrement suivant dans le niveau courant :
gboolean gtk_tree_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter);

Modifie l'itrateur courant pour passer au suivant, la fonction retourne FALSE si il n'y a pas de suivant.

2004 Jean-Robert SCHLOSSER

11 / 41

Les listes et arbres en GTK+

Les traitements des itrateurs

Savoir si un enregistrement a des fils :


gboolean gtk_tree_model_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter);

Savoir combien un enregistrement a de fils :


gint gtk_tree_model_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter);

Accder au premier fils d'un enregistrement :


gboolean gtk_tree_model_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent);

Accder au nime fils d'un enregistrement :


gboolean gtk_tree_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n);

(le premier enregistrement porte le numro 0) Accder au pre d'un enregistrement :


gboolean gtk_tree_model_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child);

Les traitements des chemins


Crer un nouvel objet chemin :
GtkTreePath *gtk_tree_path_new(void);

Convertir une chane de caractres ("2:3:0:1") en chemin :


GtkTreePath *gtk_tree_path_new_from_string(const gchar *path);

Crer un chemin partir d'une liste d'entiers :


GtkTreePath *gtk_tree_path_new_from_indices(gint first_index, ..., -1);

Convertir un chemin en chane de caractres :


gchar *gtk_tree_path_to_string(GtkTreePath *path);

Accder au chemin du premier enregistrement ("0") :


GtkTreePath *gtk_tree_path_new_first(void);

Ajouter un index (le numro d'un fils) un chemin :


void gtk_tree_path_append_index(GtkTreePath *path, gint index);

Ajouter un index (numro de parent de plus au niveau) au dbut d'un chemin :


void gtk_tree_path_prepend_index(GtkTreePath *path, gint index);

Calculer le niveau d'imbrication d'un chemin :


gint gtk_tree_path_get_depth(GtkTreePath *path);

Convertir un chemin en tableau d'entiers :


gint *gtk_tree_path_get_indices(GtkTreePath *path);

Libre la mmoire alloue pour un chemin :


void gtk_tree_path_free(GtkTreePath *path);

2004 Jean-Robert SCHLOSSER

12 / 41

Les listes et arbres en GTK+

Les traitements des chemins

Copie la valeur d'un chemin :


GtkTreePath *gtk_tree_path_copy(const GtkTreePath *path);

Compare deux chemins :


gint gtk_tree_path_compare(const GtkTreePath *a, const GtkTreePath *b);

renvoie 0 s'ils sont gaux, -1 si a est avant b, 1 si a est aprs b. Dplace le chemin vers l'enregistrement suivant, au mme niveau :
void gtk_tree_path_next(GtkTreePath *path);

Dplace le chemin vers l'enregistrement prcdent, au mme niveau :


gboolean gtk_tree_path_prev(GtkTreePath *path);

renvoie FALSE si il n'y a plus d'enregistrement prcdent ce niveau. Fait pointer le chemin vers le pre de l'enregistrement :
gboolean gtk_tree_path_up(GtkTreePath *path);

renvoie FALSE si l'enregistrement n'a pas de pre. Fait pointer l'enregistrement vers le premier fils de l'enregistrement :
void gtk_tree_path_down(GtkTreePath *path);

Vrifie la descendance entre deux chemins :


gboolean gtk_tree_path_is_ancestor(GtkTreePath *path, GtkTreePath *descendant); gboolean gtk_tree_path_is_descendant(GtkTreePath *path, GtkTreePath *ancestor);

Les traitements des rfrences


Vrifie si une rfrence est non NULL et valide (les donnes correspondantes peuvent avoir t supprimes) :
gboolean gtk_tree_row_reference_valid(GtkTreeRowReference *reference);

Libre la mmoire alloue pour une rfrence :


void gtk_tree_row_reference_free(GtkTreeRowReference *reference);

Copie la valeur d'une rfrence :


GtkTreeRowReference* gtk_tree_row_reference_copy (GtkTreeRowReference *reference);

La cration des lignes


Il n'est pas obligatoire d'ajouter les nouvelles lignes une extrmit de la liste, il est aussi possible d'ajouter une ligne juste avant, ou juste aprs, une liste connue par son itrateur. Pour cela, on dispose des fonctions :
void gtk_list_store_insert_before (GtkListStore *list_store, GtkTreeIter *iter, GtkTreeIter *sibling); void gtk_list_store_insert_after (GtkListStore *list_store, GtkTreeIter *iter, GtkTreeIter *sibling); void gtk_tree_store_insert_before (GtkListStore *list_store, GtkTreeIter *iter, GtkTreeIter *parent, GtkTreeIter *sibling);

2004 Jean-Robert SCHLOSSER

13 / 41

Les listes et arbres en GTK+

La cration des lignes

void gtk_tree_store_insert_after (GtkListStore *list_store, GtkTreeIter *iter, GtkTreeIter *parent, GtkTreeIter *sibling);

Dans le cas des arbres la gestion est puissante, donc un peu plus complexe que dans les listes simples :

si parent et sibling sont NULL, alors la nouvelle ligne est ajoute au dbut ou la fin du niveau le plus haut, si parent a une valeur, mais que sibling est NULL, alors, la nouvelle ligne est ajoute au dbut ou la fin de la liste des enfants de parent,
si sibling a une valeur, alors parent doit tre NULL ou avoir tre le parent de sibling, dans ce cas, la nouvelle ligne est ajoute juste avant, ou juste aprs la ligne pointe par sibling.

Le tri des lignes


Les lments de base pour les tris
La base des mthodes pour obtenir une prsentation tries des lignes est indpendante du type de modle (liste simple ou arbre). La premire tape consiste obtenir une copie triable du magasin par les instructions :
GtkTreeSortable *sortable; sortable = GTK_TREE_SORTABLE(store);

ensuite, il faut crire une fonction de comparaison dont le prototype est le suivant :
gint* GtkTreeIterCompareFunc(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data);

le premier paramtre donne bien sr le modle concern, mais attention, il est de type GtkTreeModel donc il il faudra gnralement le transtyper en GtkListStore ou GtkTreeStore pour l'utiliser, les deux paramtres suivants sont des itrateurs sur les lignes comparer, tandis que le dernier paramtre est un pointeur sur les donnes passes lors de l'attachement en tant que fonction de rappel (il est habituel de passer ici le numro correspondant au type de tri) ; la valeur de retour doit tre 0 si les deux lignes sont quivalentes, -1 si la ligne pointe par a est suprieure la ligne pointe par b , et 1 sinon. Il est possible d'crire une fonction qui fait un traitement diffrent en fonction du numro de type de tri ; il est aussi possible d'crire autant de fonction que de types de tri. Au dpart, il tait prvu de dfinir un type de tri par colonne, mais en fait, rien n'oblige a utiliser les valeurs de cette colonne comme critre pour raliser les tests, et donc le numro de colonne correspond dsormais un type de test ; une des consquence de cela est que le numro du critre de tri n'est pas limit au nombre de colonnes du magasin. Il faut maintenant lier la fonction de tri au magasin en lui associant un numro de critre ( column_id , voir l'explication ci-dessus). on utilise pour cela la fonction :
void gtk_tree_sortable_set_sort_func (GtkTreeSortable *sortable, gint sort_column_id, GtkTreeIterCompareFunc sort_func, gpointer user_data, GtkDestroyNotify destroy);

Classiquement, le premier paramtre (sortable) est le magasin concern, dans sa version triable ,

2004 Jean-Robert SCHLOSSER

14 / 41

Les listes et arbres en GTK+

Les lments de base pour les tris

le deuxime paramtre est le numro (sort_column_id) du critre de tri, le troisime paramtre (sort_func) est la fonction de comparaison dfinie prcdemment, le quatrime paramtre (user_data) est un pointeur vers les donnes passer l la fonction de comparaison, on l'utilise souvent pour indiquer le critre de tri lorsqu'on ne dveloppe qu'une seule fonction de comparaison le dernier paramtre (destroy) est une fonction de rappel qui est appele en cas de destruction des donnes utilisateurs (user_data), la plupart du temps on passe la valeur NULL pour ce paramtre. Il est possible de dfinir un tri par dfaut pour le magasin en utilisant la fonction :
void gtk_tree_sortable_set_default_sort_func (GtkTreeSortable *sortable, GtkTreeIterCompareFunc sort_func, gpointer user_data, GtkDestroyNotify destroy);

Le premier paramtre (sortable) est le magasin concern, dans sa version triable , le deuxime paramtre (sort_func) est la fonction de comparaison dfinie prcdemment, le troisime paramtre (user_data) est un pointeur vers les donnes passer l la fonction de comparaison, on l'utilise souvent pour indiquer le critre de tri lorsqu'on ne dveloppe qu'une seule fonction de comparaison le dernier paramtre (destroy) est une fonction de rappel qui est appele en cas de destruction des donnes utilisateurs (user_data), la plupart du temps on passe la valeur NULL pour ce paramtre. Si le troisime paramtre (user_data) a la valeur NULL, alors, par dfaut le magasin n'est pas tri.

Le tri dans le magasin


Il est possible de trier le magasin en dfinissant un critre de tri grce la fonction :
void gtk_tree_sortable_set_sort_column_id (GtkTreeSortable *sortable, gint sort_column_id, GtkSortType order);

Rappel : le critre de tri est dfini sous le nom de sort_column_id dans le nom de la fonction aussi bien que dans le nom du paramtre en raison de la smantique initiale de la fonctionnalit de tri. Le dernier paramtre indique l'ordre de tri en utilisant les constantes : GTK_SORT_ASCENDING et GTK_SORT_DESCENDING. Si la valeur du critre de tri est GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, alors, c'est le critre de tri par dfaut qui est utilis. Si la fonction de tri par dfaut est NULL alors, le magasin redevient non tri ce qui permet d'utiliser d'autres formes de tri3.

Le tri par les titres de colonne


Une autre mthode de tri consiste faire en sorte que le tri se dclenche en cliquant sur les titres de colonne. Cette mthode est simple mettre en uvre et naturelle pour l'utilisateur. Il suffit d'associer un critre de tri chacune des colonnes qui doivent permettre le tri lors de la cration de l'afficheur. on utilise pour cela la fonction :
void gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column, gint sort_column_id);

Le premier click tri dans l'ordre ascendant, le second dans l'ordre descendant.

3 Cette dernire phrase est conforme au comportement dcrit dans la documentation officielle, mais il semble que a ne fonctionne pas en version 2.2.4 ; revrifier en 2.4. 2004 Jean-Robert SCHLOSSER 15 / 41

Les listes et arbres en GTK+

Le magasin tri intermdiaire

Le magasin tri intermdiaire


Il se peut que vous ne souhaitiez pas trier directement les donnes dans le magasin ; par exemple parce que vous utilisez plusieurs afficheurs diffrents sur le mme magasin. La technique Pour cela, nous allons utiliser un magasin intermdiaire, qui va grer le tri. Ce magasin est cr par la fonction :
GtkTreeModel* gtk_tree_model_sort_new_with_model(GtkTreeModel *child_model);

Le paramtre child_model reprsente bien videmment le magasin dans lequel se trouvent vos donnes. Comme ce magasin est de type GtkListStore ou GtkTreeStore, il faudra le transtyper grce la macro GTK_TREE_MODEL(). Ensuite, c'est sur ce magasin que vous appliquez vos fonctions de tri et que vous appliquez vos afficheurs. Un exemple vaut mieux qu'un long discours :
/* Exemple de magasin intermdiaire pour le tri */ GtkListStore *store; /* le magasin principal */ GtkTreeModel *sortstore; /* le magasin intermdiaire */ GtkTreeSortable *sortable; /* le magasin triable */ store = gtk_list_store_new(5, G_TYPE_STRING, /* [...] */ ); /* remplissage du magasin avec les donnes */ /* Cration du magasin intermdiaire */ sortstore = gtk_tree_model_sort_new_with_model(store); /* Application des fonctions de tri */ gtk_tree_sortable_set_sort_func (sortable, 25, sort_iter_compare_func, NULL, NULL); /* ventuellement, appel de gtk_tree_sortable_set_sort_column_id() */ /* Cration de l'afficheur */ GtkWidget *tree; GtkCellRenderer *renderer; GtkTreeViewColumn *column; tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(sortstore)); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes ("Auteur", renderer, "text", 0, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); /* ventuellement appel de (gtk_tree_view_column_set_sort_column_id) */ gtk_tree_view_column_set_sort_column_id(column, 25);

Remarque sur les itrateurs et les chemins Comme les donnes ne sont pas dans le mme ordre dans le magasin principal et dans le magasin tri, les itrateurs ne correspondent pas. Il existe donc des fonctions de conversion pour passer d'un magasin l'autre :

2004 Jean-Robert SCHLOSSER

16 / 41

Les listes et arbres en GTK+

Remarque sur les itrateurs et les chemins

pour calculer les valeurs dans le magasin principal, connaissant les valeurs dans le magasin tri :
GtkTreePath* gtk_tree_model_sort_convert_path_to_child_path (GtkTreeModelSort *tree_model_sort, GtkTreePath *sorted_path); void gtk_tree_model_sort_convert_iter_to_child_iter (GtkTreeModelSort *tree_model_sort, GtkTreeIter *child_iter, GtkTreeIter *sorted_iter);

pour calculer les valeurs dans le magasin tri, connaissant les valeurs dans le magasin principal :
GtkTreePath* gtk_tree_model_sort_convert_child_path_to_path (GtkTreeModelSort *tree_model_sort, GtkTreePath *child_path); void gtk_tree_model_sort_convert_child_iter_to_iter (GtkTreeModelSort *tree_model_sort, GtkTreeIter *sort_iter, GtkTreeIter *child_iter);

Il peut aussi tre intressant de connatre le magasin principal lorsque l'on connat la magasin tri. pour cela il existe la fonction :
GtkTreeModel *gtk_tree_model_sort_get_model(GtkTreeModelSort *tree_model);

et donc, le paramtre, c'est le magasin tri, le rsultat, c'est le magasin principal. Et pour illustrer tout a, l'exemple d'une fonction qui supprime la ligne slectionne :
/* Suppression de la ligne slectionne */ /* en dbut de programme on a cr une slection unique */ GtkWidget *tree; GtkTreeSelection *select; select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)); gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE); /* voici maintenant le contenu de la fonction de suppression */ GtkTreeIter sortiter, iter; GtkTreeModelSort *sortstore; GtkListStore *store; if (gtk_tree_selection_get_selected(select, &sortstore, &sortiter)) { store = GTK_LIST_STORE(gtk_tree_model_sort_get_model(sortstore)); gtk_tree_model_sort_convert_iter_to_child_iter (sortstore, &iter, &sortiter); gtk_list_store_remove(store, &iter); }

Les signaux
Signal row-changed row-deleted row-has-child-toggled Fonction de rappel void user_function(GtkTreeModel *treemodel,
GtkTreePath *arg1, GtkTreeIter *arg2, gpointer user_data); void user_function(GtkTreeModel *treemodel, GtkTreePath *arg1, gpointer user_data); void user_function(GtkTreeModel *treemodel, GtkTreePath *arg1, GtkTreeIter *arg2, gpointer user_data);
17 / 41

2004 Jean-Robert SCHLOSSER

Les listes et arbres en GTK+

Les signaux

Signal row-inserted

Fonction de rappel void user_function(GtkTreeModel *treemodel,


GtkTreePath *arg1, GtkTreeIter *arg2, gpointer user_data); void user_function(GtkTreeModel *treemodel, GtkTreePath *arg1, GtkTreeIter *arg2, gpointer arg3, gpointer user_data);

rows-reordered Paramtre treemodel arg1

Description Pointeur vers le magasin qui a mis le signal Chemin de la ligne concerne (attention dans le cas row-deleted , ce chemin correspond au chemin de l'ancienne ligne, mais devient un chemin non valide aou d'une autre ligne) non document dans la description de l'API de rfrence non document dans la description de l'API de rfrence Donnes passes la connexion du signal

arg2 arg3 user_data

Les changements dans l'ordre des lignes


Ceci n'est possible que pour les magasins non tris. Dans le cas des arbres, les deux itrateurs doivent tre du mme niveau, ou position doit tre NULL. Nous disposons de 2 fonctions pour les listes et deux pour les arbres :
void gtk_list_store_move_before (GtkListStore *store, GtkTreeIter *iter, GtkTreeIter *position); void gtk_list_store_move_after (GtkListStore *store, GtkTreeIter *iter, GtkTreeIter *position); void gtk_tree_store_move_before (GtkTreeStore *store, GtkTreeIter *iter, GtkTreeIter *position); void gtk_tree_store_move_after (GtkTreeStore *store, GtkTreeIter *iter, GtkTreeIter *position);

Ces deux fonctions sont simples, mais elles sous-entendent que l'on dispose de l'itrateur de l'autre ligne. Si position est NULL, alors, la ligne est dplace au dbut ou la fin de la liste. Il est aussi possible d'changer la place de deux lignes, dans les cas d'un arbre, ces deux lignes doivent faire partie du mme niveau, par la fonction :
void gtk_list_store_swap(GtkListStore *store, GtkTreeIter *a, GtkTreeIter *b); void gtk_tree_store_swap(GtkTreeStore *store, GtkTreeIter *a, GtkTreeIter *b);

Enfin il est possible de rordonner les lignes grce aux fonctions :


void gtk_list_store_reorder(GtkListStore *store, gint *new_order); void gtk_tree_store_reorder(GtkTreeStore *tree_store, GtkTreeIter *parent, gint *new_order);

2004 Jean-Robert SCHLOSSER

18 / 41

Les listes et arbres en GTK+

Les changements dans l'ordre des lignes

Ces fonctions permettent de rordonner le magasin, ou dans le cas des arbres une branche du magasin, selon un critre de tri. Ces fonctions ne sont applicables que si le magasin n'est pas tri (en utilisant gtk_tree_sortable_set_sort_column_id()). A la diffrence de le fonction de tri, l'ordre n'est pas maintenu en cas de changement dans le magasin (ajout de ligne, modification de valeur) ; il est ncessaire d'appeler la fonction reorder chaque fois que l'on souhaite refaire le classement dans le magasin.

Le parcours du magasin
Il existe plusieurs mthodes pour se dplacer dans les donnes du magasin en fonction de ce que l'on veut faire. Le parcours de l'ensemble du magasin l'aide d'une fonction de rappel est relativement simple (par exemple pour sauvegarder le contenu sur un fichier disque). Cependant la gestion de la fonction d'itration (passage l'lment suivant) peut devenir relativement complexe dans le cas d'un arbre.

Parcours global avec la fonction de rappel


Cette mthode fait partie de GtkTreeModel, elle est donc applicable indiffremment aux listes et aux arbres, mais elle ncessite un transtypage de votre magasin en magasin gnrique avec la macro GTK_TREE_MODEL(). Cette mthode se passe en deux temps : premirement, il faut crire la fonction excuter pour chaque enregistrement de donnes, comme elle va tre utilise en fonction de rappel, elle doit avoir un prototype impos qui est le suivant :
gboolean user_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);

Cette fonction vous permet donc d'accder aux donnes par un chemin ou un itrateur et disposez d'un accs aux donnes passes lors de la connexion de cette fonction. Si la fonction renvoie la valeur TRUE, le parcours du magasin s'arrte. Pour rcuprer les donnes, la technique la plus simple est certainement l'utilisation de la fonction :
void gtk_tree_model_get(GtkTreeModel *model, GtkTreeIter *iter, ..., -1);

Les deux premiers paramtres sont videmment ceux que vous avez reu en paramtres d'entre de votre fonction, tandis qu'en suite vous avez une liste, termine par -1, de couples numro de colonne/pointeur sur la valeur. Il s'agit de pointeurs sur la valeur puisque c'est la fonction qui va modifier ces valeurs. ensuite, il faut demander l'excution de cette fonction sur toutes les donnes du magasin en appelant :
void gtk_tree_model_foreach(GtkTreeModel *model, GtkTreeModelForeachFunc func, gpointer user_data);

2004 Jean-Robert SCHLOSSER

19 / 41

Les listes et arbres en GTK+

Parcours global avec la fonction de rappel

Rien de trs original, mais comme un exemple4 vaut mieux qu'un long discours :
/* Exemple de dump d'un arbre */ gboolean foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { gchar *name; gdouble prix; gint depth; gtk_tree_model_get(model, iter, 0, &name, 2, &prix, -1); depth = gtk_tree_store_iter_depth(GTK_TREE_STORE(model), iter); if(depth) g_fprintf(user_data, "+%s:%0.2f\n", name, prix); else g_fprintf(user_data, "%s\n", name); g_free(name); /* librer la mmoire pour les chanes de caractres */ } return FALSE; /* continuer parcourir l'arbre */

gboolean xx_save_in_file(const gchar *filename) { FILE *fp; /* Sauvegarde du magasin dans un fichier */ fp = fopen(filename,"w"); if(fp == NULL) return FALSE; gtk_tree_model_foreach(GTK_TREE_MODEL(store), foreach_func, fp); fclose(fp); } return TRUE;

En grant la boucle d'itration


Cette technique reste simple dans le cas d'une liste, c'est un peu plus compliqu pour un arbre ( cause de la gestion du niveau d'imbrication). Bon, commenons par le dbut, donc rcuprons l'itrateur du premier lment par la fonction :
gboolean gtk_tree_model_get_iter_first (GtkTreeModel *tree_model, GtkTreeIter *iter);

Ensuite, il faut rcuprer un itrateur sur la donne suivante :


gboolean gtk_tree_model_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter);

4 Astuce : si vous avez dans le magasin des textes convertis en UTF8 pour avoir un affichage correct des accents, il faut penser faire la conversion inverse avant d'crire dans le fichier. 2004 Jean-Robert SCHLOSSER 20 / 41

Les listes et arbres en GTK+

En grant la boucle d'itration

Dans le cas d'une liste, tout va bien ; on appelle cette fonction jusqu' ce que la valeur de retour soit FALSE. Par contre, dans le cas d'un arbre, c'est plus compliqu car cette fonction permet d'accder la donne suivante de mme niveau. Donc avant, de passer la suite, il faut vrifier si la donne n'a pas de fils par :
gboolean gtk_tree_model_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter);

Si c'est le cas, il faut rcuprer le premier fils par :


gboolean gtk_tree_model_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent);

Il ne reste plus qu' parcourir les fils comme vu plus haut, en n'oubliant pas de s'occuper de leurs enfants s'ils en ont. Et bien oui, un parcours d'arbre a finit presque toujours par une fonction rcursive. Alors, la voici :
/* Exemple de parcours d'arbre */ gboolean browse_tree(GtkTreeModel *model, GtkTreeIter *parent, gint level) { gboolean ret; GtkTreeIter iter; if(parent == NULL) ret = gtk_tree_model_get_iter_first(model, &iter); else ret = gtk_tree_model_iter_children(model, &iter, parent); /* au cas o le (sous-)arbre explorer serait vide */ if(!ret) return FALSE; do { gtk_tree_model_get(model, &iter, /* donnes rcuprer, */ -1); /** TRAITEMENT des donnes de l'enregistrement **/ if(gtk_tree_model_iter_has_child(model, &iter)) browse_tree(model, &iter, level+1); } until (!gtk_tree_model_iter_next(model, &iter)); return TRUE;

/* le premier appel se fait par : */ browse_tree(model, NULL, 0);

2004 Jean-Robert SCHLOSSER

21 / 41

Les listes et arbres en GTK+

La gestion de l'affichage en dtail

LA GESTION DE L'AFFICHAGE EN DTAIL


Pour rsumer, l'affichage est une table constitue de colonnes qui contiennent un titre puis des cellules permettant d'afficher les valeurs contenues dans un magasin. Certaines caractristiques sont applicables au niveau de l'afficheur, tandis que d'autre se rapportent la colonne ou la cellule.

L'afficheur
L'afficheur lui-mme n'apporte pas normment de fonctionnalits. Il sert avant tout dfinir le lien avec le magasin de donnes.

Les liens avec le magasin


Il est possible de crer un afficheur sans liaison avec un magasin par la fonction :
GtkWidget *gtk_tree_view_new(void);

On peut ensuite l'associer un modle avec la fonction :


void gtk_tree_view_set_model(GtkTreeView *tree_view, GtkTreeModel *model);

si l'afficheur tait dj li un magasin, ce lien est supprim avant d'en crer un autre avec le magasin pass en paramtre. Il peut aussi tre intressant de connatre le magasin qui contient les donnes affiches, pour cela, on utilise la fonction :
GtkTreeModel *gtk_tree_view_get_model(GtkTreeView *tree_view);

La configuration de l'afficheur
Masquer les titres de colonnes Pour choisir si les titres de colonnes doivent tre afficher ou non (ils le sont par dfaut), on utilise la fonction :
void gtk_tree_view_set_headers_visible (GtkTreeView *tree_view, gboolean headers_visible);

tandis qu'il est possible de connatre l'tat courant par :


gboolean gtk_tree_view_get_headers_visible(GtkTreeView *tree_view);

Autoriser le click sur les titres de colonne Il est possible de choisir si le click sur le titre de colonne est gr ou non en utilisant la fonction :
void gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view, gboolean setting);

Remarque : l'utilisation d'une fonction de tri sur une colonne active automatiquement la gestion du click sur les titres de colonne. Gestion des marques de suivi des lignes Il est possible d'indiquer que l'on souhaite faciliter la lecture des lignes pour l'utilisateur (par un choix de couleur de fond alterne pour chaque ligne) par la fonction :
void gtk_tree_view_set_rules_hint (GtkTreeView *tree_view, gboolean setting);

et il est possible de connatre l'tat courant par :


gboolean gtk_tree_view_get_rules_hint (GtkTreeView *tree_view);

2004 Jean-Robert SCHLOSSER

22 / 41

Les listes et arbres en GTK+

Gestion des marques de suivi des lignes

Remarque : la documentation officielle de l'API donne quelques prcision et conseils supplmentaires : N'utilisez pas cette fonction uniquement parce que vous prfrez l'apparence avec les marques ; ceci est une question de thme. Certains thmes vont afficher les lignes avec des couleurs alternes mme si les marques ne sont pas actives, et les utilisateurs qui prfrent cette apparence peuvent choisir ces thmes. Vous ne devriez utiliser cette fonction que comme une information smantique pour le moteur de thme pour lui indiquer que votre afficheur rend utile les marques de lignes pour une raison fonctionnelle (parce qu'il a un grand nombre de colonnes en gnral). Gestion des regroupements de lignes Lorsque l'on utilise un afficheur d'arbre, il est possible de masque (collapse) ou afficher (expand) les enfants d'une ligne. Par dfaut, seul le plus haut niveau est affich. Plusieurs fonctions permettent de jouer avec ce fonctionnement : pour afficher tous les lments :
void gtk_tree_view_expand_all(GtkTreeView *tree_view);

pour masquer tous les lments, sauf ceux de plus haut niveau :
void gtk_tree_view_collapse_all(GtkTreeView *tree_view);

pour afficher les enfants directs d'une ligne (et tous ses parents si besoin) :
void gtk_tree_view_expand_to_path(GtkTreeView *tree_view, GtkTreePath *path);

pour afficher la descendance d'une ligne :


gboolean gtk_tree_view_expand_row(GtkTreeView *tree_view, GtkTreePath *path, gboolean open_all);

si open_all est TRUE, alors on affiche toute la descendance, sinon seuls les enfants directs sont affichs. pour masquer les enfants d'un ligne (s'il y en a) :
gboolean gtk_tree_view_collapse_row(GtkTreeView *tree_view, GtkTreePath *path);

pour savoir si une ligne a ses enfants affichs ou masqus :


gboolean gtk_tree_view_row_expanded(GtkTreeView *tree_view, GtkTreePath *path);

pour choisir la colonne qui affiche les icnes de regroupement :


void gtk_tree_view_set_expander_column (GtkTreeView *tree_view, GtkTreeViewColumn *column);

si la colonne est NULL alors l'indicateur de regroupement est dans la premire colonne. enfin, pour appliquer une fonction sur toutes les lignes affiches :
void gtk_tree_view_map_expanded_rows(GtkTreeView *tree_view, GtkTreeViewMappingFunc func, gpointer data);

avec une fonction de rappel qui a le prototype suivant :


void func(GtkTreeView *tree_view, GtkTreePath *path, gpointer user_data);

La gestion des colonnes


Les fonctions qui permettent de grer les colonnes, mme si elles font partie de l'objet GtkTreeView, sont prsentes plus loin avec la prsentation dtaille des colonnes pour plus de clart dans l'expos.

2004 Jean-Robert SCHLOSSER

23 / 41

Les listes et arbres en GTK+

La fonctionnalit de recherche interactive

La fonctionnalit de recherche interactive


Ceci ne semble pas fonctionner en GTK+ 2.2.4 Le principe ressemble fort la gestion des tris. D'abord, il faut crire une fonction de comparaison qui a le prototype suivant :
gboolean equal_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data);

ensuite, il faut dire que l'on souhaite utiliser cette fonction pour la recherche intractive :
void gtk_tree_view_set_search_equal_func(GtkTreeView *tree_view, GtkTreeViewSearchEqualFunc search_equal_func, gpointer search_user_data, GtkDestroyNotify search_destroy);

ensuite, il faut choisir la colonne du magasin o est appliqu la recherche :


void gtk_tree_view_set_search_column (GtkTreeView *tree_view, gint column);

ceci active en mme temps la recherche. Il est aussi possible d'activer ou dsactiver la recherche par :
void gtk_tree_view_set_enable_search(GtkTreeView *tree_view, gboolean enable_search);

Enfin, il est possible de connatre le paramtrage courant de la recherche par les fonctions :
gboolean gint gtk_tree_view_get_enable_search (GtkTreeView *tree_view); gtk_tree_view_get_search_column (GtkTreeView *tree_view); (GtkTreeView *tree_view);

GtkTreeViewSearchEqualFunc gtk_tree_view_get_search_equal_func

L'ajout d'ascenseurs
On voudra souvent accompagner l'afficheur de barres de dfilement, horizontale et/ou verticales. L'objet GtkTreeView fait partie des quelques widgets (avec GtkTextView et GtkLayout) qui ont t conus en prvoyant cet ajout ; il est donc trs simple. Il faut crer une fentre avec barres de dfilement par la fonction :
GtkWidget* gtk_scrolled_window_new (GtkAdjustment *hadjustment, GtkAdjustment *vadjustment);

Les paramtres permettent de dfinir trs prcisment les caractristiques des barres de dfilement, comme le pas de celles-ci. En gnral, on laissera faire GTK+ en passant la valeur NULL. Ensuite, il faut prciser la gestion des barres de dfilement avec la fonction :
void gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window, GtkPolicyType hscroll_policy, GtkPolicyType vscroll_policy);

Pour les deux derniers paramtres, on GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER.

utilise

les

constantes

GTK_POLICY_ALWAYS,

Maintenant, il ne reste plus qu' insrer l'afficheur dans cette fentre avec gtk_container_add().

2004 Jean-Robert SCHLOSSER

24 / 41

Les listes et arbres en GTK+

L'ajout d'ascenseurs

Comme un exemple vaut mieux qu'un long discours :


/* Exemple d'afficheur d'arbre avec ascenseurs */ GtkTreeStore *store; GtkWidget *tree, *pScrollbar; tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); pScrollbar = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pScrollbar), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(pScrollbar), tree);

La colonne
Les colonnes constituent un lment intermdiaire dans la constitution de notre afficheur.

La gestion des afficheurs lmentaires


Nous avons vu plus haut qu'il est possible facilement de crer une colonne avec un afficheur lmentaire grce gtk_tree_view_column_new_with_attributes(). En fait, il est possible de dcomposer toutes les oprations. GTK+ autorise mme de mettre plusieurs afficheurs lmentaires dans une mme colonne. Pour mettre plusieurs afficheurs lmentaires dans une mme cellule, le principe ressemble beaucoup la Hbox ; on utilise les fonctions :
void gtk_tree_view_column_pack_start(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, gboolean expand);

et
void gtk_tree_view_column_pack_end(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, gboolean expand);

le paramtre expand FALSE indique qu'aucun espace supplmentaire ne doit tre utilis par l'afficheur lmentaire ; cet espace est reparti entre les afficheurs pour lesquels il est TRUE. Il est possible de rcuprer la liste des afficheurs contenus dans une colonne par la fonction :
Glist *gtk_tree_view_column_get_cell_renderers(GtkTreeViewColumn *tree_column);

Cette liste est doublement-chane, elle n'est pas dans un ordre particulier. Aprs usage, il faut penser librer la mmoire avec g_list_free(). Il est possible de supprimer tous les afficheurs lmentaires contenus dans une colonne par la fonction :
void gtk_tree_view_column_clear(GtkTreeViewColumn *tree_column);

Cependant, dans ce cas, il faut ajouter les attributs5 aux afficheurs lmentaires ensuite grce aux fonctions :
void gtk_tree_view_column_set_attributes(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell_renderer, ..., NULL);

5 Pour bien comprendre la gestion des attributs, on peut lire en parallle La gestion des attributs un tout petit peu plus loin (page 28). 2004 Jean-Robert SCHLOSSER 25 / 41

Les listes et arbres en GTK+

La gestion des afficheurs lmentaires

et
void gtk_tree_view_column_add_attribute(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell_renderer, const gchar *attribute, gint column);

ainsi que :
void gtk_tree_view_column_clear_attributes (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell_renderer);

La premire fonction permet de fixer une liste de couples attribut/valeur pour l'afficheur lmentaire selon un syntaxe proche de celle de gtk_tree_view_column_new_with_attributes(). Attention, cette fonction efface toutes les affectations prexistantes. La deuxime fonction affecte la valeur d'un attribut en complment des affectations existantes. La dernire fonction permet bien videmment d'effacer tous les affectations existantes de valeur aux attributs. En complment, il est possible de grer un espacement entre les afficheurs lmentaires grce aux fonctions :
void gtk_tree_view_column_set_spacing (GtkTreeViewColumn *tree_column, gint spacing);

et
gint gtk_tree_view_column_get_spacing(GtkTreeViewColumn *tree_column);

la valeur de l'espacement est mesure en pixels.

Visibilit et redimensionnement
Parmi les paramtres de prsentation que l'on peut grer au niveau d'une colonne, on trouve la visibilit et le redimensionnement de la largeur. Visibilit d'une colonne Pour afficher ou masquer une colonne, on utilise la fonction :
void gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column, gboolean visible);

tandis que pour connatre l'tat courant, on utilise :


gboolean gtk_tree_view_column_get_visible (GtkTreeViewColumn *tree_column);

Redimensionnement de la largeur d'une colonne Une colonne dispose d'une politique de gestion de sa largeur. Cette politique est dfini au travers des constantes suivantes : GTK_TREE_VIEW_COLUMN_GROW_ONLY, dans ce cas, en cas de changement des valeurs du magasin, la largeur peut augmenter si besoin, mais elle ne rtrcit pas ; GTK_TREE_VIEW_COLUMN_AUTOSIZE, dans ce cas, la largeur s'adapte automatiquement chaque changement dans le magasin ; GTK_TREE_VIEW_COLUMN_FIXED, dans ce cas la colonne a une largeur fixe, ce qui peut entraner que certains affichage soient tronqus. Pour grer la politique de largeur d'une colonne, on utilise les fonctions :
void gtk_tree_view_column_set_sizing(GtkTreeViewColumn *tree_column, GtkTreeViewColumnSizing type);

2004 Jean-Robert SCHLOSSER

26 / 41

Les listes et arbres en GTK+

Redimensionnement de la largeur d'une colonne

et
GtkTreeViewColumnSizing gtk_tree_view_column_get_sizing (GtkTreeViewColumn *tree_column);

Pour grer la largeur d'une colonne (en pixels), on utilise :


gint gtk_tree_view_column_get_width(GtkTreeViewColumn *tree_column);

cette fonction renvoie la largeur relle de la colonne ;


gint gtk_tree_view_column_get_fixed_width(GtkTreeViewColumn *tree_column);

cette fonction renvoie la largeur impose de la colonne (celle-ci peut tre diffrente de la largeur relle, voire plus loin les largeur min et max) ;
void gtk_tree_view_column_set_fixed_width (GtkTreeViewColumn *tree_column, gint fixed_width);

cette fonction impose une largeur fixe la colonne, la largeur relle sera calcule en tenant compte des largeurs min et max, cette fonction n'a de sens que si la politique de largeur de la colonne est GTK_TREE_VIEW_COLUMN_FIXED ;
void gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column, gint min_width);

cette fonction impose une largeur minimum la colonne ;


gint gtk_tree_view_column_get_min_width(GtkTreeViewColumn *tree_column);

cette fonction renvoie la largeur minimum de la colonne ;


void gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column, gint max_width);

cette fonction impose une largeur maximum la colonne, une largeur de -1 signifie qu'il n'y a pas de maximum ;
gint gtk_tree_view_column_get_max_width(GtkTreeViewColumn *tree_column);

cette fonction renvoie la largeur maximum de la colonne ; Dans le cas GTK_TREE_VIEW_COLUMN_FIXED, la largeur relle est calcule en prenant le minimum si la largeur fixe est infrieure ce minimum, le maximum si la largeur fixe est suprieure ce maximum, et la largeur fixe sinon. En plus de la gestion des largeurs prcdente, une colonne a une gestion spcifique ; elle s'tend automatiquement pour couvrir toute la largeur allou au GtkTreeView. Par dfaut, cette colonne est la dernire, mais il est possible de modifier ce comportement avec :
void gtk_tree_view_column_set_expand (GtkTreeViewColumn *treecolumn, gboolean expand);

L'espace disponible est alors rparti quitablement entre toutes les colonnes ayant cet attribut TRUE. On peut connatre l'tat de l'attribut par :
gboolean gtk_tree_view_column_get_expand (GtkTreeViewColumn *tree_column);

Enfin, dernier point, il est possible de permettre l'utilisateur de redimensionner lui-mme la largeur de colonne en tranant le sparateur de droite de cette colonne ; pour cela, on utilise la fonction :
void gtk_tree_view_column_set_resizable (GtkTreeViewColumn *tree_column, gboolean resizable);

2004 Jean-Robert SCHLOSSER

27 / 41

Les listes et arbres en GTK+

Redimensionnement de la largeur d'une colonne

Si le dernier paramtre est GTK_TREE_VIEW_COLUMN_AUTOSIZE GTK_TREE_VIEW_COLUMN_GROW_ONLY.

TRUE alors,

et

que elle

la

politique de largeur est passe automatiquement

Et pour connatre la valeur de cette autorisation, il y a la fonction :


gboolean gtk_tree_view_column_get_resizable(GtkTreeViewColumn *tree_column);

Autres attributs de la colonne


En fait, il ne reste plus qu'une seule caractristique : le titre. Gestion du titre de la colonne D'abord, commenons par rappeler que l'affichage/masquage du titre doit tre identique sur toutes les colonnes, il est donc du ressort de l'afficheur global ( cf. Masquer les titres de colonnes page 22). Donc la seule chose que l'on puisse modifier, c'est le contenu du titre, ce que l'on fait avec :
void gtk_tree_view_column_set_title (GtkTreeViewColumn *tree_column, const gchar *title);

Et bien sr, on peut en rcuprer la valeur par :


G_CONST_RETURN gchar *gtk_tree_view_column_get_title (GtkTreeViewColumn *tree_column);

Mais il est aussi possible de remplacer le label du titre de colonne par un autre widget en utilisant la fonction :
void gtk_tree_view_column_set_widget(GtkTreeViewColumn *tree_column, GtkWidget *widget);

et de rcuprer ce widget par :


GtkWidget* gtk_tree_view_column_get_widget(GtkTreeViewColumn *tree_column);

La cellule
L'afficheur de cellule lmentaire ( Cell Renderer ) est un lment fondamental du systme. C'est au travers de ses attributs que se fixe une part importante du fonctionnement de l'afficheur.

La gestion des attributs


La notion d'attribut Un afficheur lmentaire dispose d'un nombre important de paramtres lui indiquant ce qu'il doit afficher. Ce sont ses attributs. L'essentiel de la gestion de l'affichage se fait en associant des valeurs aux attributs de l'afficheur lmentaire. Fondamentalement, on associe un numro de colonne (du magasin sous-jacent) un attribut pour qu' chaque ligne l'afficheur utilise la valeur correspondante dans le magasin. C'est ce que j'appelle les attributs variables Il est aussi possible d'affecter une valeur fixe qui sera utilise pour toute la colonne. C'est ce que j'appelle les attributs fixes.

2004 Jean-Robert SCHLOSSER

28 / 41

Les listes et arbres en GTK+

Les attributs variables

Les attributs variables Pour un mme afficheur lmentaire on peut associer plusieurs attributs, chacun une colonne diffrente du magasin. Comme en plus, il peut y avoir plusieurs afficheurs lmentaire dans une mme colonne, on voit bien qu'il n'est pas possible de remonter une colonne du magasin en partant d'une colonne de l'afficheur, ou mme d'un afficheur lmentaire. L'affectation des attributs variables se fait en utilisant les fonctions vues dans la description des colonnes (cf. La gestion des afficheurs lmentaires page 25). Pour mmoire, les principales fonctions sont : gtk_tree_view_column_new_with_attributes() gtk_tree_view_column_set_attributes() gtk_tree_view_column_add_attribute() gtk_tree_view_column_clear_attributes() Les attributs constants Il arrive aussi que l'on veuille dfinir certaines caractristiques communes pour toute la colonne, par exemple la police d'affichage du texte. Dans ce cas, plutt que d'affecter une colonne du modle la valeur de l'attribut de l'afficheur lmentaire, on fixe directement la valeur de cette attribut par la fonction :
void g_object_set(gpointer object, ..., NULL);

Le premier paramtre est bien sr l'afficheur lmentaire concern, normalement transtyp par la macro G_OBJECT() ; ensuite on trouve une liste de couples nom d'attribut (format texte de type gchar *) / valeur de l'attribut (le type dpend de l'attribut), cette liste est termine par un NULL. Le rsultat est imprvisible, ou tout au moins inconnu de l'auteur et non prcis dans la documentation officielle, lorsque l'on utilise le mme attribut la fois comme constant et variable.

Les 3 types d'afficheurs lmentaires


GTK+ fournit 3 afficheurs lmentaires6 : 1 pour l'affichage de texte (mme si c'est une valeur numrique ou boolenne), 1 pour l'affichage d'icnes, un pour l'affichage de case cocher. Afficheur de texte L'afficheur de texte permet d'afficher les valeurs des donnes du magasin sous forme textuelle en choisissant de nombreuses caractristiques d'affichage. On cre un afficheur lmentaire texte par la fonction :
GtkCellRenderer* gtk_cell_renderer_text_new (void);

Ensuite on fixe les caractristiques de l'affichage au travers des attributs (cf. Les attributs variables et Les attributs constants). L'attribut text permet de dfinir la lien entre le texte affich et la donne. Pour ne pas alourdir la lecture de ce document, les autres attributs sont prsents en annexe. Afficheur d'icne L'afficheur d'icne permet d'afficher dans les cellules de petites images fournies sous forme de GdkPixBuf ou de StockItem. On cre un afficheur d'icne par la fonction :
GtkCellRenderer* gtk_cell_renderer_pixbuf_new(void);
6 La version 2.4 de GTK+ devrait apporter un modle supplmentaire qui permettra de filtrer les donnes. 2004 Jean-Robert SCHLOSSER 29 / 41

Les listes et arbres en GTK+

Afficheur d'icne

Ensuite on fixe les caractristiques de l'affichage au travers des attributs (cf. Les attributs variables et Les attributs constants). L'attribut pixbuf permet de dfinir avec l'image afficher, tandis que stock-id dfinit l'icne lorsque l'on utilise des StockItem. Pour ne pas alourdir la lecture de ce document, les autres attributs sont prsents en annexe. Afficheur binaire L'afficheur binaire permet d'afficher dans les cellules dune valeur boolenne sous forme de case cocher ou de bouton radio. On cre un afficheur binaire par la fonction :
GtkCellRenderer* gtk_cell_renderer_toggle_new(void);

Ensuite on fixe les caractristiques de l'affichage au travers des attributs (cf. Les attributs variables et Les attributs constants). L'attribut active permet de dfinir si la case doit tre coche ou non. Pour ne pas alourdir la lecture de ce document, les autres attributs sont prsents en annexe. Il est possible de choisir si l'affichage doit se faire sous forme de bouton radio plutt qu'une case cocher en utilisant la fonction suivante plutt qu'un attribut constant :
void gtk_cell_renderer_toggle_set_radio (GtkCellRendererToggle *toggle, gboolean radio);

Il reste la charge du programme de s'assurer que dans le cas du bouton radio, une seule case est active la fois.

Fonction d'affichage spcifique


Parfois, on a envie d'avoir un formattage plus prcis que celui qui est autoris par les attributs de l'afficheur lmentaire. C'est par exemple le cas pour les valeurs flottantes lorsque l'on veut choisir le nombre de chiffres aprs la virgule. GTK+ nous offre une mthode7 pour prparer l'affichage avant le passage de l'afficheur lmentaire. Il suffit d'utiliser la fonction :
void gtk_tree_view_column_set_cell_data_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *renderer, GtkTreeCellDataFunc func, gpointer func_data, GtkDestroyNotify destroy);

La fonction de rappel doit avoir le prototype suivant :


void user_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data);

Dans cette fonction de rappel, il devient possible de positionner les attributs de l'afficheur lmentaire avec plus de souplesse. Attention cependant, si un attribut doit tre forc dans certains cas et pas d'autres, il faut lui en supprimer la valeur quand c'est inutile.

7 Cette mthode peut s'avrer malgr tout un peu gourmande en ressources lorsqu'il y a un grand nombre d'enregistrements afficher, et ainsi ralentir l'application. 2004 Jean-Robert SCHLOSSER 30 / 41

Les listes et arbres en GTK+

Fonction d'affichage spcifique

Un bon exemple vaut mieux qu'un long discours :


/* Exemple data_cell_function */ void double_display_function(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { gdouble montant; guint colnum = GPOINTER_TO_UINT(user_data); gchar buf[20]; gtk_tree_model_get(model, iter, colnum, &montant, -1); if(montant > 0.0) { g_snprintf(buf, sizeof(buf), "%.2f", montant); g_object_set(renderer, "text", buf, "visible", TRUE, NULL); } else { g_object_set(renderer, "visible", FALSE, NULL); } [...] */

} /*

renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes ("Montant",renderer,NULL); gtk_tree_view_column_set_cell_data_func(column, renderer, double_display_function, GUINT_TO_POINTER(4), NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);

dition sur place


Afficheur de texte
Il est possible de modifier la valeur valeur d'une cellule texte en saisissant une nouvelle valeur dans la case. Pour l'utilisateur, lorsque cette fonction est active, il suffit de cliquer dans une case d'une ligne slectionne (par un click prcdent), de saisir la nouvelle valeur puis de valider par la touche Entre ou en cliquant en dehors de la cellule en cours de saisie ; l'utilisateur peut renoncer changer la valeur de la cellule en utilisant la touche Escape8 . Sur le plan de la programmation, il faut autoriser la saisie dans la cellule en donnant la valeur TRUE l'attribut editable de l'afficheur lmentaire. Si toute la colonne doit tre ditable, alors on utilise un attribut constant dont on fixe la valeur par :
g_object_set(renderer, "editable", TRUE, NULL);

(rien n'empche de grouper cet attribut avec d'autres attributs constants.) mais il est aussi possible de lier cet attribut une colonne dont les valeurs sont boolennes (cf. Les attributs variables page 29). Ensuite, il faut encore aller modifier le contenu du magasin lorsque l'utilisateur a saisi une nouvelle valeur dans la cellule. Pour cela, il faut rcuprer le signal edited de l'afficheur lmentaire par la fonction g_signal_connect().

8 Touche Echap sur la plupart des claviers franais. 2004 Jean-Robert SCHLOSSER 31 / 41

Les listes et arbres en GTK+

Afficheur de texte

Pour ce signal, il faut dfinir une fonction de rappel dont le prototype est le suivant :
void user_function(GtkCellRendererText *renderer, gchar *path_string, gchar *new_text, gpointer user_data);

Le deuxime paramtre donne le chemin, sous forme de chane de caractres, de la ligne concerne par la saisie. Le troisime paramtre fournit le texte (en chane de caractres mme pour une valeur numrique) qui a t saisi. Le dernier paramtre renvoie classiquement les donnes qui ont t fournies lors de l'attachement du signal. Comme il est dlicat de remonter au numro de colonne du magasin en partant de l'afficheur lmentaire (cf. Remonter de la colonne d'un afficheur la colonne d'un magasin page 37), il est fortement recommand de mettre ce numro de colonne comme donnes utilisateur lors de l'attachement du signal (ou au moins parmi les donnes). L'autre solution consiste attacher le numro de colonne l'afficheur comme dcrit page 37.

Afficheur d'icne
Aucune possibilit d'dition en ligne n'est prvue.

Afficheur binaire
Selon un principe analogue l'afficheur texte, il faut rendre la cellule modifiable en positionnant TRUE l'attribut activatable . Si toute la colonne doit tre ditable, alors on utilise un attribut constant dont on fixe la valeur par :
g_object_set(renderer, "activatable", TRUE, NULL);

(rien n'empche de grouper cet attribut avec d'autres attributs constants.) mais il est aussi possible de lier cet attribut une colonne dont les valeurs sont boolennes (cf. Les attributs variables page 29). Ensuite, il faut encore aller modifier le contenu du magasin lorsque l'utilisateur a saisi une nouvelle valeur dans la cellule. Pour cela, il faut rcuprer le signal toggled de l'afficheur lmentaire par la fonction g_signal_connect(). Pour ce signal, il faut dfinir une fonction de rappel dont le prototype est le suivant :
void user_function(GtkCellRendererToggle *renderer, gchar *path_string, gpointer user_data);

Le deuxime paramtre donne le chemin, sous forme de chane de caractres, de la ligne concerne par la saisie. Le dernier paramtre renvoie classiquement les donnes qui ont t fournies lors de l'attachement du signal. Lorsque l'utilisateur clique sur la case, ni l'apparence de la case cocher ni la valeur dans le magasin n'est modifie, pour que l'apparence change, il faut que le programme aille modifier la valeur dans le magasin (il faut d'abord lire l'ancienne valeur dans le magasin pour pouvoir forcer la valeur oppose).

Informations diverses
Double-click sur une colonne
Il est possible de rcuprer facilement l'information du double click dans une colonne en rcuprant le signal row-activated . Il faut connecter le signal au niveau de l'afficheur. La fonction de rappel doit avoir le prototype suivant :
void user_function(GtkTreeView *treeview, GtkTreePath *arg1, GtkTreeViewColumn *arg2, gpointer user_data);

2004 Jean-Robert SCHLOSSER

32 / 41

Les listes et arbres en GTK+

Double-click sur une colonne

En fait, lorsqu'on regarde les informations disponibles, on s'aperoit que l'on dispose de la colonne, mais aussi de la ligne (chemin). Cependant, il ne faut pas en dduire qu'il est simple de remonter la colonne correspondante du magasin (cf. Remonter de la colonne d'un afficheur la colonne d'un magasin page 37).

Gestion d'un menu contextuel


La gestion d'un menu contextuel se fait gnralement par un click sur le bouton droit de la souris. Comme tous les widgets de GTK+, l'afficheur de listes et d'arbres gre ce click, il suffit de connecter le signal button-press-event . Dans la fonction de traitement, il faut s'assurer que c'est bien le bouton droit de la souris qui a t utilis. Habituellement, le menu contextuel doit aussi pouvoir tre accessible sur l'appui de la touche Shift-F10 sans utilisation de la souris. Pour cela, il faut connecter le signal popup-menu l'afficheur. La gestion d'un menu pop-up sort du cadre de ce document.

2004 Jean-Robert SCHLOSSER

33 / 41

Les listes et arbres en GTK+

La gestion des slections en dtail

LA GESTION DES SLECTIONS EN DTAIL


L'objet selection est systmatiquement cr en mme temps que chaque afficheur. En fait, cet objet n'existe que pour clarifier l'API. Il suffit de le rcuprer avec la fonction gtk_tree_view_get_selection() (voir plus : La slection page 9)

Rcuprer les lments slectionns


Rcuprer une slection unique
Dans le cas d'une slection simple (GTK_SELECTION_SINGLE ou GTK_SELECTION_BROWSE), il est facile de rcuprer un itrateur qui pointe sur la donne slectionne. Comme vu plus haut, il est possible de rcuprer le magasin et l'itrateur de la donnes par la fonction :
gboolean gtk_tree_selection_get_selected (GtkTreeSelection *selection, GtkTreeModel **model, GtkTreeIter *iter);

La fonction retourne une valeur vraie lorsqu'un lment est effectivement slectionn. Quelques prcisions complmentaires : Cette fonction ne doit pas tre utilise si le mode est GTK_SELECTION_MULTIPLE. Si l'appel de la fonction a seulement pour objet de savoir si il y a une ligne slectionne ou non, il est possible de mettre NULL pour le paramtre iter .

Rcuprer la liste des lments slectionns


Fonction de rcupration d'une slection Il est possible de rcuprer la liste des slections sous la forme d'une liste de chemins :
Glist *gtk_tree_selection_get_selected_rows (GtkTreeSelection *selection, GtkTreeModel **model);

Le dernier paramtre permet rcuprer la valeur du magasin associ ; on peut mettre NULL si on n'a pas besoin de cette valeur. Transformation des chemins en rfrences La liste des lments slectionns est fournie au travers de chemins. Mais ces chemins ne sont valables que tant que le contenu du magasin ne varie pas. Si dans le traitement que vous envisagez de faire vous souhaitez supprimer, ajouter ou dplacer des donnes, il vous faudra convertir ces chemins en rfrences. Parcours de la liste La liste des lments slectionns est au format d'une liste doublement chanes de la glib. Cette bibliothque met notre disposition les outils dont nous avons besoin. Pour appeler une fonction pour chaque lment de la liste :
void g_list_foreach(GList *list, GFunc func, gpointer user_data);

La fonction de traitement doit avoir le prototype suivant :


void func(gpointer data, gpointer user_data);

Le premier paramtre fournit l'lment sur lequel doit s'appliquer la fonction ; le deuxime paramtre fournit les donnes qui ont t passes lors de l'appel de g_list_foreach().

2004 Jean-Robert SCHLOSSER

34 / 41

Les listes et arbres en GTK+

Parcours de la liste

Et si l'on souhaite grer soi-mme le parcours de la liste, on peut utiliser les fonctions : pour connatre le nombre d'lments slectionns :
gint gtk_tree_selection_count_selected_rows(GtkTreeSelection *selection);

pour accder aux donnes (le chemin) partir d'un lment :


Glist *element; chemin = element->data;

pour accder au premier ou au dernier lment :


Glist *g_list_first(GList *list); Glist *g_list_last(GList *list);

pour accder l'lment suivant ou prcdent :


Glist *g_list_next(GList *list); Glist *g_list_previous(GList *list);

(en fait, il s'agit de macros, ce qui limite un peu leur utilisation, par exemple, il n'est pas possible de les utiliser directement comme fonction de rappel) pour accder au n-ime lment :
Glist *g_list_nth(GList *list, guint n);

ou pour accder directement aux donnes du n-ime lment (c'est dire au chemin) :
gpointer g_list_nth_data(GList *list, guint n);

Il existe d'autres fonctions de manipulation de liste dans la glib, mais celles-ci devraient tre suffisantes pour le cas prsent. Libration de la mmoire Aprs avoir utilis les informations fournies par gtk_tree_selection_get_selected_rows(), il faut librer la mmoire correspondante (les chemins, et la liste elle-mme) par :
g_list_foreach (list, gtk_tree_path_free, NULL); g_list_free (list);

Parcourir la liste des lments slectionns


Il est aussi possible de parcourir directement (au niveau gtk) les lments slectionns grce la fonction :
void gtk_tree_selection_selected_foreach(GtkTreeSelection *selection, GtkTreeSelectionForeachFunc func, gpointer data);

la fonction de rappel doit avoir le prototype suivant :


gboolean func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);

Le premier paramtre est le magasin, le deuxime le chemin, le troisime l'itrateur, et le dernier les donnes fournies lors de l'appel gtk_tree_selection_selected_foreach(). Si la fonction renvoie la valeur TRUE, le parcours de la slection s'arrte. Attention : cette fonction semble sduisante, mais elle souffre d'une limitation importante : il ne faut pas ajouter, supprimer ou dplacer les donnes dans le magasin au cours du traitement effectu.

2004 Jean-Robert SCHLOSSER

35 / 41

Les listes et arbres en GTK+

Changement de la slection

Changement de la slection
Changer la slection par programme
Si l'utilisateur peut grer la slection en utilisant le souris et/ou le clavier, il est aussi possible de la modifier par programme. Pour cela, GTK+ met notre disposition les fonctions suivantes :
void gtk_tree_selection_select_iter(GtkTreeSelection *selection, GtkTreeIter *iter); void gtk_tree_selection_unselect_iter(GtkTreeSelection *selection, GtkTreeIter *iter); void gtk_tree_selection_select_path(GtkTreeSelection *selection, GtkTreePath *path); void gtk_tree_selection_unselect_path(GtkTreeSelection *selection, GtkTreePath *path); void gtk_tree_selection_select_all(GtkTreeSelection *selection); void gtk_tree_selection_unselect_all(GtkTreeSelection *selection); void gtk_tree_selection_select_range(GtkTreeSelection *selection, GtkTreePath *start_path, GtkTreePath *end_path); void gtk_tree_selection_unselect_range(GtkTreeSelection *selection, GtkTreePath *start_path, GtkTreePath *end_path);

La majorit de ces fonctions ont bien videmment un comportement qui dpend du mode de slection en cours (GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE). Si le mode est SINGLE ou BROWSE, la fonction gtk_tree_selection_select_iter() dselectionnera la ligne prcdemment slectionne avant d'en slectionner une nouvelle ; tandis que gtk_tree_selection_select_all() n'aura pas d'effet.

Grer le changement de slection


Il est possible d'tre au courant que la slection a change en rcuprant le signal changed avec une fonction de rappel dont le prototype est le suivant :
void user_function(GtkTreeSelection *treeselection, gpointer user_data);

Attention : ce signal peut n'tre mis qu'une seule fois lors de la slection d'un groupe de lignes et il peut tre mis alors qu'il n'y a pas de changement dans la slection. Mais on peut faire mieux, c'est dire tre prvenu chaque fois que l'utilisateur souhaite slectionner ou dslectionner une ligne pour donner notre accord (par programme). pour cela, on utilise la fonction :
void gtk_tree_selection_set_select_function(GtkTreeSelection *selection, GtkTreeSelectionFunc func, gpointer data, GtkDestroyNotify destroy);

Cette fonction utilise une fonction de rappel ayant le prototype :


gboolean user_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean currently_selected, gpointer data);

Le paramtre path permet de connatre la ligne concerne par le changement de slection, tandis que currently_selected donne l'tat actuel de la slection (avant l'action utilisateur). Si la fonction retourne TRUE, alors le changement de slection est effectu, sinon, il n'est pas pris en compte.

2004 Jean-Robert SCHLOSSER

36 / 41

Les listes et arbres en GTK+

Trucs et astuces divers

TRUCS ET ASTUCES DIVERS


Remonter de la colonne d'un afficheur la colonne d'un magasin
La mthode complte
Lorsque l'on connat une colonne de l'afficheur et que l'on veut remonter la colonne correspondante du magasin, la technique n'est pas simple. En fait, c'est tout bonnement impossible sauf faire certaines hypothses, parce qu'une colonne d'afficheur peut tre lie plusieurs colonnes du magasin : parce la colonne d'affichage contient plusieurs afficheurs lmentaires, parce que l'afficheur lmentaire a plusieurs attributs lis des colonnes diffrentes du magasin. Nous supposerons donc dans la suite qu'il n'y a qu'un seul afficheur dans la colonne concerne, et que nous recherchons la colonne du magasin associe l'attribut principal de l'afficheur lmentaire ( text pour un afficheur de texte, pixbuf pour un afficheur d'icnes et active pour un afficheur boolen. Donc, procdons par tape : depuis la colonne de l'afficheur, remontons l'afficheur lmentaire par :
Glist *gtk_tree_view_column_get_cell_renderers(GtkTreeViewColumn *tree_column);

puis :
renderer = CellList->data;

ensuite, il faudrait savoir quel type d'afficheur lmentaire on a affaire, mais on va simplement rechercher les attributs qui nous intressent : ... et l, on est coinc : pas moyen de remonter la colonne, l'objet GtkTreeViewColumn ne fournit pas de fonction gtk_tree_view_column_get_attribute(), la fonction g_objetc_get() sur l'afficheur lmentaire ne nous rendrait elle qu'un attribut constant, ce qui n'est pas ce que l'on recherche.

Une astuce pour s'en sortir


Puisqu'il n'est pas possible de remonter de l'afficheur lmentaire la colonne du magasin avec les fonctions du noyau de GTK, la solution consiste ajouter cette information dans la colonne ou l'afficheur lmentaire lors de la constitution de la vue. Attention : il s'agit d'une information thoriquement redondante il y a donc un risque d'incohrence et c'est au programmeur de garantir la validit de cette information. Choisir entre colonne et afficheur lmentaire Associer l'information de colonne du magasin l'objet colonne de l'afficheur, c'est un moyen de simplifier au maximum lorsque l'on ne dispose, au dpart, que de cet objet. Cependant, comme il peut y avoir plusieurs afficheurs lmentaires dans une mme colonne, cela peut poser un problme. Par contre certaines fonctions de rappel9 fournissent un pointeur sur l'afficheur lmentaire, il est alors plus judicieux de stocker l'information avec l'afficheur lmentaire. Associer le numro de colonne Pour associer une information a un objet, on utilise la fonction :
void g_object_set_data(GObject *object, const gchar *key, gpointer data);

et pour retrouver la valeur, on utilise la fonction :


gpointer g_object_get_data(GObject *object, const gchar *key);
9 La fonction de rappel du signal editable d'un afficheur lmentaire par exemple. 2004 Jean-Robert SCHLOSSER 37 / 41

Les listes et arbres en GTK+

Associer le numro de colonne

Ces deux fonctions peuvent bien entendu tre utilises aussi bien sur l'objet colonne de l'afficheur que sur l'afficheur lmentaire. En pratique, cela donne les fragments de code suivants :
/* Exemple 1 de passage de la colonne afficheur au magasin */ GtkTreeView *view,; GtkTreeViewColumn *column; guint ncol; column = gtk_tree_view_column_new(); g_object_set_data (G_OBJECT(column), "columnnum", GUINT_TO_POINTER(COL_XXX)); /* [...] */

ncol = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(column), "columnnum");

/* Exemple 2 de passage de la colonne afficheur au magasin */ GtkTreeView *view,; GtkTreeViewColumn *column; GtkCellRenderer *renderer; guint ncol; renderer = gtk_cell_renderer_text_new(); g_object_set_data (G_OBJECT(renderer), "columnnum", GUINT_TO_POINTER(COL_XXX)); column = gtk_tree_view_column_new_with_attributes ("Titre XXX", renderer, "text", COL_XXX, NULL); /* [...] */

ncol = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(renderer), "columnnum");

2004 Jean-Robert SCHLOSSER

38 / 41

Les listes et arbres en GTK+

Annexes

ANNEXES
Dfinitions des constantes
Types de colonne
G_TYPE_NONE G_TYPE_INTERFACE G_TYPE_CHAR G_TYPE_UCHAR G_TYPE_BOOLEAN G_TYPE_INT G_TYPE_UINT G_TYPE_LONG G_TYPE_ULONG G_TYPE_INT64 G_TYPE_UINT64 G_TYPE_ENUM G_TYPE_FLAGS G_TYPE_FLOAT G_TYPE_DOUBLE G_TYPE_STRING G_TYPE_POINTER G_TYPE_BOXED G_TYPE_PARAM G_TYPE_OBJECT

Modes de slection
GTK_SELECTION_NONE GTK_SELECTION_SINGLE GTK_SELECTION_BROWSE GTK_SELECTION_MULTIPLE

Pas de slection possible Slection de 0 ou 1 lment la fois Slection d'exactement 1 lment Slection de plusieurs lments, contigus ou non, en utilisant les touches Shift et Ctrl

Attributs des afficheurs lmentaires


Afficheur de texte
Attribut "attributes"
"background" "background-gdk" "background-set" "editable" "editable-set" "family" "family-set" "font" "font-desc" "foreground" "foreground-gdk"

Type PangoAttrList
gchararray GdkColor gboolean gboolean gboolean gchararray gboolean gchararray PangoFontDescr iption gchararray GdkColor

R/W Description R/W A list of style attributes to apply to the text of the renderer. Background color as a string.
R/W Background color as a GdkColor. R/W Whether this tag affects the background color. R/W Whether the text can be modified by the user. R/W Whether this tag affects text editability. R/W Name of the font family, Helvetica, Times, Monospace. R/W Font description as a string. R/W Font description as a PangoFontDescription struct. W

e.g.

Sans,

R/W Whether this tag affects the font family.

Foreground color as a string.

R/W Foreground color as a GdkColor.

2004 Jean-Robert SCHLOSSER

39 / 41

Les listes et arbres en GTK+

Afficheur de texte

Attribut "foreground-set"
"language"

Type gboolean
gchararray

"language-set" "markup" "rise" "rise-set" "scale" "scale-set"

gboolean gchararray gint gboolean gdouble gboolean

R/W Description R/W Whether this tag affects the foreground color. R/W The language this text is in, as an ISO code. Pango can use this as a hint when rendering the text. If you don't understand this parameter, you probably don't need it. R/W Whether this tag affects the language the text is rendered as. W Marked up text to render.
R/W Offset of text above the baseline (below the baseline if rise is negative). R/W Whether this tag affects the rise. R/W Font scaling factor. R/W Whether this tag scales the font size by a factor. R/W Whether or not to keep all text in a single paragraph. R/W Font size. R/W Font size in points. R/W Whether this tag affects the font size. R/W Font stretch. R/W Whether this tag affects the font stretch. R/W Whether to strike through the text. R/W Whether this tag affects strikethrough. R/W Font style. R/W Whether this tag affects the font style. R/W Text to render. R/W Style of underline for this text. R/W Whether this tag affects underlining. R/W Font variant. R/W Whether this tag affects the font variant. R/W Font weight. R/W Whether this tag affects the font weight.

"single-paragraph-mode" gboolean "size" "size-points" "size-set" "stretch" "stretch-set" "strikethrough" "strikethrough-set" "style" "style-set" "text" "underline" "underline-set" "variant" "variant-set" "weight" "weight-set" gint gdouble gboolean PangoStretch gboolean gboolean gboolean PangoStyle gboolean gchararray PangoUnderline gboolean PangoVariant gboolean gint gboolean

2004 Jean-Robert SCHLOSSER

40 / 41

Les listes et arbres en GTK+

Afficheur d'icne

Afficheur d'icne
Attribut
"pixbuf" "pixbuf-expander-open" "stock-detail" "stock-id" "stock-size"

Type GdkPixbuf
GdkPixbuf gchararray gchararray

"pixbuf-expander-closed" GdkPixbuf

R/W Description R/W The pixbuf to render. R/W Pixbuf for closed expander.
R/W R/W R/W

Pixbuf for open expander. Render detail to pass to the theme engine. The stock ID of the stock icon to render. The size of the rendered icon.

GtkIconSize R/W

Afficheur boolen
Attribut "activatable"
"active" "inconsistent" "radio"

Type gboolean
gboolean gboolean gboolean

R/W Description R/W The toggle button can be activated. R/W The toggle state of the button. R/W The inconsistent state of the button.
R/W

Draw the toggle button as a radio button.

Documentation
API officielle
Glib Gobject Pango ATK GdkPixbuf GDK GTK http://developer.gnome.org/doc/API/2.0/glib/index.html http://developer.gnome.org/doc/API/2.0/gobject/index.html http://developer.gnome.org/doc/API/2.0/pango/index.html http://developer.gnome.org/doc/API/2.0/atk/index.html http://developer.gnome.org/doc/API/2.0/gdk-pixbuf/index.html http://developer.gnome.org/doc/API/2.0/gdk/index.html http://developer.gnome.org/doc/API/2.0/gtk/index.html

Autres tutoriels
par Tim-Philipp Mller par gtk-fr.org http://scentric.net/tutorial http://www.gtk-fr.org/index.php?page=cours&id=23 en anglais en franais

Reste faire
Prsenter le fonctionnement du Drag and drop Enrichir les Trucs et astuces

2004 Jean-Robert SCHLOSSER

41 / 41

You might also like