Visual Basic .Net:Classe Treeview
Un article de WikiTuto.
Sommaire |
Explication
Dans les arbres, nous allons pouvoir faire plein de choses. En effet, les arbres sont une manière extrêmement pratique de structurer les données, et au moment même où vous lisez ces lignes, je suis certain que vous avez déjà en tête plusieurs exemples de situations où des données informatiques sont organisées - et peuvent donc être représentées - sous forme d'arbre. L'exemple le plus tartignol - c'est évidemment celui que je choisirai - est celui d'un disque dur, avec ses répertoires contenant d'autres répertoires, qui contiennent d'autres répertoires, etc. Et d'ailleurs, si vous voulez imaginer à quoi ressemble un contrôle Treeview, il suffit de penser à la partie gauche de l'explorateur de Windows. Ce n'est pas pour rien.
Noeud
Alors, le Tree d'un Treeview, c'est quoi ? C'est un sac de noeuds, au propre comme au figuré.
Chaque noeud (Node, en anglais, objet de la classe TreeNode) fait partie d'une collection (TreeNodeCollection) des noeuds qui ont le même noeud parent que lui (tous les sous-répertoires immédiats d'un même répertoire).
Dans l'autre sens, chaque noeud pointe sur une collection, celle des noeuds dont il est lui-même le père (tous ses sous-répertoires immédiats).
Manipulation des noeuds
Manipuler un Treeview, cela revient donc à manipuler des collections de noeuds ! Ce qui signifie :
- ajouter un noeud dans une collection, via Add (qui l'ajoute à la fin) ou Insert (qui l'ajoute à l'emplacement spécifié)
- supprimer un noeud d'une collection, via les trois méthodes déjà) rencontrées à propos des listes : Remove, RemoveAt et Clear.
Evènements
Côté événements, les Treeview proposent plusieurs possibilités originales. On peut notamment gérer le fait qu'un noeud soit déployé, par les événements BeforeExpand ou AfterExpand (selon qu'on veuille agir juste avant ou juste après le déploiement du noeud). On peut également gérer le fait qu'un noeud soit replié, avec les événements BeforeCollapse et AfterCollapse (même différence entre les deux).
Exemple Treeview Explorateur
L'exemple de programmation qui va suivre est pour ainsi dire complètement idiot, car comme nous le verrons plus loin, il existe un moyen beaucoup plus rapide de parvenir au résultat dont nous allons laborieusement accoucher ici. Mais, et les mauvais esprits n'ont qu'à bien se tenir, cet exemple possède une vertu pédagogique, dans la mesure où il nous permettra de mettre le doigt dans des techniques un peu... euh, disons... stimulantes.
Liste des répertoires
Bon, on sait maintenant presque assez pour s'amuser à fabriquer une réplique grandeur nature de la partie gauche de l'explorateur Windows. Pour cela, il nous manque encore quelques petits détails. En particulier, il nous faut un moyen de récupérer, à partir d'un répertoire donné, la liste des sous-répertoires qu'il contient. Ça, ça ne s'invente pas, et c'est pour cela qu'existe la fonction :
Directory.GetDirectories(répertoire)
qui renvoie, sous forme d'un tableau de chaînes, l'ensemble des sous-répertoires du répertoire passé en argument. Sauf que pour que ça marche, il ne faudra pas oublier d'écrire, tout en haut du programme :
Imports System.IO
Parce que sinon, le compilateur ne sait pas qui est ce Directory dont vous lui parlez, encore moins quelle est cette méthode GetDirectories qui lui est attachée, et vous flanquera illico une erreur de compilation. Rappelez-vous, les espaces de noms, nous en avons déjà parlé...
Allons-y maintenant pour de bon. Notre code va s'articuler autour d'une petite procédure que nous appellerons chaque fois que nous en aurons besoin pour mettre à jour notre Treeview. Cette procédure que j'appelle Explor :
- réclame comme paramètre entrant (ByVal) le noeud dans lequel on veut chercher et afficher les sous-répertoires
- purge les sous-noeuds existants par un Clear
- ajoute comme sous-noeud de ce noeud tous les éléments fournis par GetDirectories (c'est-à-dire tous les sous-répertoires), via une boucle For Each.
Private Sub Explor(ByVal Node As TreeNode) Node.Nodes.Clear() Dim s As String For Each s In Directory.GetDirectories(Node.FullPath) Node.Nodes.Add(Path.GetFileName(s)) Next s End Sub
Il faut remarquer que s récupère à chaque fois le nom complet du répertoire (avec le chemin). D'où l'emploi de la fonction Path.GetFileName, qui purge le chemin et nous restitue le nom du répertoire proprement dit.
Et d'une.
Sous-répertoires
Et de deux, il faut qu'en cas de clic sur un noeud, notre procédure Explor soit déclenchée pour chacun des sous-répertoires du noeud en question (on a en quelque sorte à chaque fois un coup d'avance : on affiche dans l'arbre les répertoires situés deux niveaux en-dessous du répertoire actif : comme cela, parmi les sous-répertoires directs du sous-répertoire actif, le Treeview affichera différemment ceux qui contiennent quelque chose et ceux qui ne contiennent rien. On aura donc :
Private Sub TreeView1_AfterExpand(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterExpand Dim z As TreeNode For Each z In e.Node.Nodes Explor(z) Next z End Sub
Il ne manque plus qu'un détail : amorcer la pompe lors du chargement de la Form, en donnant comme point de départ la racine du lecteur C:, et en considérant que le premier - et le seul - noeud présent dans notre Treeview porte l'index zéro :
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
TreeView1.Nodes.Add("c:\")
Explor(TreeView1.Nodes.Item(0))
End Sub
Avec tout cela, on obtient un joli explorateur qui fonctionne, en nous donnant un truc dans ce genre :
Alternative
Bien évidemment, on pourrait programmer l'affaire très différemment, par exemple en remplissant d'avance, une bonne fois pour toutes, le Treeview avec tous les répertoires du disque dur. Mais ça ne serait pas plus facile à programmer, et cela s'avèrerait en réalité moins performant.
Icône du répertoire
Pour que notre explorateur soit parfait, nickel-chrome comme ceux vus à la TV, il lui manque toutefois un petit détail : qu'à chaque noeud soit associé non seulement le petit "+" ou la simple ligne, mais également l'icône du répertoire ouvert ou fermé, selon les circonstances.
C'est ici que le contrôle ImageList, dont nous avons parlé juste avant, va nous rendre un fier service. Il nous suffit d'aller attraper quelque part deux jolies images, l'une d'un répertoire ouvert, l'autre d'un répertoire fermé, et de les mettre dans un contrôle ImageList.
Ensuite, associons notre contrôle ImageList au Treeview, par la propriété... ImageList de ce dernier.
A présent, modifions légèrement notre procédure Explor, en ajoutant deux instructions :
Private Sub Explor(ByVal Node As TreeNode) Node.Nodes.Clear() Dim s As String Dim z As TreeNode For Each s In Directory.GetDirectories(Node.FullPath) z = Node.Nodes.Add(Path.GetFileName(s)) z.ImageIndex = 1 z.SelectedImageIndex = 0 Next s End Sub
Il ne reste plus qu'à faire de même dans la procédure Form1_Load, et le tour est joué :
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim z As TreeNode
z = TreeView1.Nodes.Add("c:\")
Explor(z)
z.ImageIndex = 1
z.SelectedImageIndex = 0
End Sub
Remarques
A proprement parler, et pour qui a été élevé dans les canons de l'algorithmique rigoriste, les lignes du genre :
z = Node.Nodes.Add(Path.GetFileName(s))
sont une pure profanation. En effet, elles impliquent qu'on puisse à la fois appliquer une méthode (Add en l'occurrence) et affecter une variable, le tout d'un même élan. VB.Net autorise donc ce genre d'écriture hérétique, de même qu'il permet, nous en avons déjà parlé, d'affecter une variable tout en la déclarant
On peut même trouver sous la plume de certains programmeurs des lignes proprement sataniques, qui consistent tout à la fois à déclarer une variable, à l'affecter et à appliquer une méthode :
Dim z as TreeNode = Node.Nodes.Add(Path.GetfileName(s))
Alors, ce type d'écriture est un peu comme les voitures qui roulent à 250 km/h : c'est en vente libre, et c'est bien pratique pour gagner du temps, mais si on veut rester en vie, on n'est pas obligé de les acheter, et encore moins de s'en servir. A bon entendeur...
Voir aussi
- La classe Listbox
- La classe Combobox
- La classe CheckedListBox
- La classe ImageList
- La classe Treeview
- Retour au sommaire
Source : Christophe Darmangeat




