Les TreeModelSort
et TreeModelFilter
sont des modèles d'arbre qui s'intercalent entre le TreeModel
de base (un TreeStore
ou un ListStore
)
et le TreeView
pour fournir un modèle modifié en conservant
la structure d'origine du modèle de base. Ces modèles interposables implémentent
les interfaces TreeModel
et TreeSortable
mais ne fournissent aucune méthode pour insérer ou retirer des lignes dans le
modèle, il faut insérer ou retirer ces lignes dans le magasin de données sous-jacent.
Le TreeModelSort
fournit un modèle dans lequel les lignes
sont toujours classées, le TreeModelFilter
fournit un modèle
contenant un sous-ensemble des lignes du modèle de base.
Ces modèles peuvent être reliés sur une longueur arbitraire, si désiré. Par
exemple, un TreeModelFilter
peut avoir un enfant
TreeModelSort
qui peut peut avoir un enfant
TreeModelFilter
et ainsi de suite. Tant qu'il existe
un TreeStore
ou un ListStore
comme point de départ de la chaine, cela devrait fonctionner. Sous
PyGTK :2.0 et 2.2 les objets TreeModelSort
et
TreeModelFilter
ne fonctionnent pas avec le protocole
de mappage (mise en correspondance) de Python.
Le TreeModelSort
maintient un modèle trié du modèle
enfant indiqué dans son constructeur. L'usage principal du
TreeModelSort
est de fournir, pour un modele,
des vues multiples qui peuvent être classées diversement. Lorsque l'on a plusieurs
vues d'un même modèle, toute opération de tri se répercute dans toutes les vues.
Utiliser le TreeModelSort
permet de laisser le modèle
de départ dans son état originel pendant que les modèles de tri absorbent
toutes les opérations de tri. Pour créer un TreeModelSort
,
il faut utiliser le constructeur :
treemodelsort = gtk.TreeModelSort(child_model
)
... où child_model
est un
TreeModel
. La plupart des méthodes du
TreeModelSort
portent sur la conversion des chemins de
l'arborescence et des TreeIter
du modèle enfant
vers le modèle trié, et réciproquement :
sorted_path = treemodelsort.convert_child_path_to_path(child_path
) child_path = treemodelsort.convert_path_to_child_path(sorted_path
)
Ces méthodes de conversion de chemin renvoient None
si
le chemin donné ne peut être converti en chemin dans le modèle trié
ou dans le modèle enfant. Les méthodes de conversion du
TreeIter
sont :
sorted_iter = treemodelsort.convert_child_iter_to_iter(sorted_iter
,child_iter
) child_iter = treemodelsort.convert_iter_to_child_iter(child_iter
,sorted_iter
)
Les méthodes de conversion du TreeIter
dupliquent
l'argument converti (la valeur de retour comme le premier argument) pour
une présever une compatibilité antérieure. Il faut donner la valeur
None
au premier argument et n'utiliser que la valeur
de retour. Par exemple :
sorted_iter = treemodelsort.convert_child_iter_to_iter(None, child_iter) child_iter = treemodelsort.convert_iter_to_child_iter(None, sorted_iter)
Comme les méthodes de conversion du chemin, ces méthodes renvoient
None
si le TreeIter
indiqué ne
peut être converti.
On peut retrouver le TreeModel
enfant gràce à la
méthode get_model
().
treemodelsort.py est un exemple
simple utilisant les objets du TreeModelSort
. Les
résultats obtenus avec 6 lignes sont illustrés par
Figure 14.9, « Exemple de TreeModelSort »
Chacune des colonnes d'une fenêtre peut être réordonnée avec un click sur
son titre indépendamment des autres fenêtres. Lorsque le bouton
"ListStore
de base et cette
nouvelle ligne est affichée dans chaque fenêtre comme étant la ligne
sélectionnée.
Le TreeModelFilter
est disponible
avec PyGTK 2.4 et supérieur.
Un objet TreeModelFilter
fournit plusieurs façons
de modifier la vue du TreeModel
de base, y compris :
TreeIter
pointant sur une ligne du modèle fils et des données utilisateurs. Dans les deux cas,
si la valeur booléenne vaut TRUE
, la ligne est affichée sinon elle
est cachée.
TreeStore
.
Un objet TreeModelFilter
est crée par la méthode
TreeModel
:
treemodelfilter = treemodel.filter_new(root
=None)
... où root
est un chemin dans l'arbre du
treemodel
précisant une racine virtuelle du modèle
ou None
si la racine du treemodel
doit
être utilisée.
Indiquer une "racine virtuelle" quand on crée le
TreeModelFilter
permet de limiter la vue aux
enfants de cette ligne "racine" dans la hiérarchie du modèle fils. Ceci, bien
sûr, n'est utile que si le modèle fils est basé sur un TreeStore
.
Par exemple, on peut vouloir fournir une vue de la liste des pièces qui
composent un lecteur de CDROM distincte de la liste complète des pièces
de l'ordinateur.
Les modes de visibilité sont mutuellement exclusifs et ne peuvent être fixés qu'une seule fois ; Une fois la visibilité de la colonne ou de la fonction établie, on ne peut plus la modifier et l'autre mode ne peut plus être utilisé. Le mode de visibilité le plus simple extrait une valeur booléenne d'une colonne du modèle fils pour déterminer si la ligne doit être affichée. La visibilité colonne est fixée par :
treemodelfilter.set_visible_column(column
)
... où column
est le numéro de la colonne dans le
TreeModel
fils, de laquelle extraire les
valeurs booléennes. Par exemple, le code suivant utilise les valeurs de la
troisième colonne pour fixer la visibilité des lignes :
... treestore = gtk.TreeStore(str, str, "gboolean") ... modelfilter = treestore.filter_new() modelfilter.set_visible_column(2) ...
Ainsi, toutes les lignes du treestore
qui possèdent
la valeur TRUE
dans la troisième colonne seront affichées.
Si on veut utiliser des critères de visibilité plus complexes, une fonction visibilité devrait fournir des capacités suffisantes :
treemodelfilter.set_visible_func(func
,data
=None)
... où func
est la fonction appelée pour chaque
ligne du modèle fils afin de décider si elle doit être affichée et
data
représente les données utilisateur transmises
à la fonction func
. La fonction func
renvoie TRUE
si la ligne doit être affichée. Cette fonction
a pour signature :
def func(modele
,iter
,donnees_utilisateur
)
... où modele
est le TreeModel
fils, iter
est un TreeIter
pointant sur une ligne du modele
et
donnees_utilisateur
sont les data
passées dans la fonction.
Si on modifie le critère de visibilité, il faut utiliser :
treemodelfilter.refilter()
pour imposer un nouveau filtrage des lignes du modèle fils.
Par exemple, l'extrait de code ci-dessous illustre un
TreeModelFilter
qui affiche des lignes selon une
comparaison entre la valeur de la troisième colonne et le contenu des
données utilisateurs :
... def match_type(modele, iter, donnees_utilisateur): valeur = model.get_value(iter, 2) return valeur in donnees_utilisateur ... show_vals = ['OPEN', 'NEW', 'RESO'] liststore = gtk.ListStore(str, str, str) ... modelfilter = liststore.filter_new() modelfilter.set_visible_func(match_type, show_vals) ...
Le programme treemodelfilter.py illustre
l'utilisation de la méthode set_visible_func
().
Figure 14.10, « Exemple de visibilité d'un TreeModelFilter » montre le résultat obtenu.
En agissant sur les boutons du bas, on modifie le contenu du
TreeView
pour afficher seulement les lignes
qui correspondent à l'étiquette du bouton.
Une fonction modify permet un autre niveau de contrôle sur l'affichage du
TreeView
sur la manière dont on peut combiner
une ou plusieurs (ou toutes) colonnes présentées par le
TreeModelFilter
. Il faut utiliser un modèle fils de
base, un TreeStore
ou un ListStore
pour déterminer le nombre de lignes et la hiérarchie, mais les colonnes peuvent
être tout ce qui est indiqué dans la méthode :
treemodelfilter.set_modify_func(types
,func
,data
=None)
... où types
est une suite (liste ou tuple) précisant
le type de colonne présentes, func
est une fonction
appelée pour renvoyer la valeur pour une rangée et une colonne et
data
est un argument passé à la fonction
func
. La fonction func
a pour signature :
def func(modele
,iter
,colonne
,donnees_utilisateur
)
...où modele
est le TreeModelFilter
,
iter
le TreeIter
qui pointe sur
une ligne du modele, colonne
est le numéro de la colonne
pour laquelle une valeur est nécessaire et donnees_utilisateur
est le paramètre data
. La fonction
func
doit renvoyer une valeur correspondant au type de
colonne
.
Une fonction de modification est utile quand on souhaite fournir une colonne
de données qui doivent être générées à partir de données de colonnes du modèle
fils. Par exemple, on dispose d'une colonne contenant des dates de naissance
et on veut fournir une colonne affichant les âges ; une fonction de modification
peut générer l'information sur l'âge à partir de la date de naissance et de la date
actuelle. Un autre exemple serait de choisir l'image à afficher selon l'analyse
des données (un nom de fichier) dans une colonne. Cette action peut aussi être
réalisée par la methode set_cell_data_func
() du
TreeViewColumn
.
Généralement, avec la fonction modify, il faut convertir le
TreeIter
du TreeModelFilter
en
un TreeIter
dans le modèle fils par :
child_iter = treemodelfilter.convert_iter_to_child_iter(filter_iter
)
Bien sûr, il faut aussi retrouver le modèle fils par :
child_model = treemodelfilter.get_model()
Ceci donne accès à la ligne du modèle fils et à son contenu pour fournir la
valeur de la ligne et colonne indiquées du TreeModelFilter
.
Il existe aussi une méthode pour convertir les chemins du modèle filtre de et vers
les chemins de l'arborescence fille.
filter_iter = treemodelfilter.convert_child_iter_to_iter(child_iter
) child_path = treemodelfilter.convert_path_to_child_path(filter_path
) filter_path = treemodelfilter.convert_child_path_to_path(child_path
)
Bien sûr, il est possible de combiner les modes de visibilité et la fonction
modify pour, à la fois, filtrer les lignes et produire les colonnes. Pour
obtenir encore plus de contrôle sur la vue, il faudrait utiliser un
TreeModel
personnalisé.