I. Introduction

I-A. Qu'est-ce que Zest ?

Eclipse Zest est une boîte à outils de visualisation de graphes, basée sur SWT et Draw2D. Elle permet de construire et visualiser des graphes, soit directement par création des branches et des nœuds, soit par l'utilisation de l'abstraction JFace. Cette abstraction permet une approche par modèle, en s'affranchissant de la construction du graphe proprement dite.

Dans ce tutoriel, je vous propose d'utiliser Zest afin de représenter un graphe simple, soit directement par la construction des nœuds et branches du graphe, soit par l'utilisation de l'abstraction JFace à partir d'un modèle de données.

Ce tutoriel suppose que vous disposiez des connaissances de base sur les technologies suivantes :

I-B. Présentation de notre fil conducteur

Notre fil conducteur dans cet article sera la représentation d'un réseau routier entre villes. Chaque ville est un nœud du graphe, et chaque route est une branche du graphe. Vous avez peut-être entendu parler de ces graphes dans le problème très connu du voyageur de commerce. Nous n'entrerons pas dans ce tutoriel dans des considérations sur la théorie des graphes.

II. Notre premier graphe

II-A. Installation des outils

Pour installer Zest, ouvrez l'assistant d'installation de nouveaux plugins d'Eclipse et dans la liste sélectionnez « Graphical Editing Framework Zest Visualization Toolkit SDK », dans la section « Modeling ».

Image non disponible

II-B. Composants de Zest

Zest est basé sur les composants suivants :

  • GraphNode : un nœud du graphe ;
  • GraphConnection : une branche du graphe, qui peut être orientée ou non ;
  • GraphContainer : utilisé pour un graphe au sein d'un autre graphe ;
  • Graph : élément de base de la boîte à outils, il contient les éléments précités.

D'autre part, Zest agence les composants du graphe en utilisant différents types de rendu, appelés « layouts ». Ces layouts seront détaillés dans un prochain article. Zest peut aussi filtrer les éléments du graphe, comme peut le faire un arbre ou une table JFace.

II-C. Création de notre premier graphe

Nous allons construire notre premier graphe. Pour cela, créez une nouvelle application Eclipse RCP, en utilisant le template « RCP application with a view ». Ajoutez dans les dépendances de l'application les plugins « org.eclipse.zest.core » et « org.eclipse.zest.layouts ».

Image non disponible

Remplacez le contenu de la vue générée par l'assistant par le code ci-dessous. Notez que nous renommons la vue en « BasicGraphView ».

BasicGraphView.java
CacherSélectionnez
  1. package com.abernard.zest; 
  2.  
  3. import org.eclipse.swt.SWT; 
  4. import org.eclipse.swt.widgets.Composite; 
  5. import org.eclipse.ui.part.ViewPart; 
  6. import org.eclipse.zest.core.widgets.Graph; 
  7. import org.eclipse.zest.core.widgets.GraphConnection; 
  8. import org.eclipse.zest.core.widgets.GraphNode; 
  9. import org.eclipse.zest.layouts.LayoutStyles; 
  10. import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; 
  11.  
  12. /** 
  13.  * Cette vue contient un graphe construit programmatiquement, en construisant  
  14.  * 'a la main' les noeuds et les branches. 
  15.  *  
  16.  * @author A. Bernard 
  17.  * 
  18.  */ 
  19. public class BasicGraphView extends ViewPart { 
  20.  
  21.     /** 
  22.      * le graphe 
  23.      */ 
  24.     private Graph graph; 
  25.  
  26.     @Override 
  27.     public void createPartControl(Composite parent) { 
  28.     // Le Graph contient tous les autres objets 
  29.     graph = new Graph(parent, SWT.NONE); 
  30.  
  31.     // 1 :Les villes sont les noeuds du graphe 
  32.     GraphNode paris = new GraphNode(graph, SWT.NONE, "Paris"); 
  33.     GraphNode bordeaux = new GraphNode(graph, SWT.NONE, "Bordeaux"); 
  34.     GraphNode poitiers = new GraphNode(graph, SWT.NONE, "Poitiers"); 
  35.     GraphNode toulouse = new GraphNode(graph, SWT.NONE, "Toulouse"); 
  36.  
  37.     // 2 :Construction des branches du graphe. 
  38.     // Chaque branche affiche la distance kilometrique entre deux villes 
  39.     GraphConnection parisToulouse = new GraphConnection(graph, SWT.NONE,  
  40. 	toulouse, paris); 
  41.     parisToulouse.setText("678km"); 
  42.  
  43.     GraphConnection parisPoitiers = new GraphConnection(graph, SWT.NONE,  
  44. 	paris, poitiers); 
  45.     parisPoitiers.setText("338km"); 
  46.  
  47.     GraphConnection poitiersBordeaux = new GraphConnection(graph, SWT.NONE,  
  48. 	bordeaux, poitiers); 
  49.     poitiersBordeaux.setText("235km"); 
  50.  
  51.     GraphConnection bordeauxToulouse = new GraphConnection(graph, SWT.NONE, 
  52. 	toulouse, bordeaux); 
  53.     bordeauxToulouse.setText("244km"); 
  54.  
  55.     // 3 :Definition de l'algorithme de rendu du graphe 
  56.     // Ces layouts seront decrits dans un prochain cours 
  57.     graph.setLayoutAlgorithm(new SpringLayoutAlgorithm( 
  58. 	LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); 
  59.     } 
  60.  
  61.     @Override 
  62.     public void setFocus() { 
  63.     //  
  64.     } 
  65. } 

Les éléments de type GraphNode (bloc 1) sont les nœuds du graphe. Les éléments de type GraphConnection (bloc 2) servent à définir les branches du graphe. Enfin, on définit un layout pour le graphe (bloc 3).

Lancez l'application pour observer le résultat :

Image non disponible

Vous pouvez cliquer sur les éléments du graphe pour les réagencer. Voilà un graphe simple obtenu facilement et représentatif du problème. Néanmoins, la méthode de construction est lourde, et va vite devenir problématique au fur et à mesure que notre modèle va s'enrichir avec de nouveaux éléments.

Nous allons donc utiliser l'abstraction JFace pour représenter des modèles plus complexes dans notre graphe. C'est l'objet de la partie suivante.

III. Utilisation de l'abstraction JFace

III-A. Mise en place du modèle

Afin de construire notre graphe, nous avons besoin dans un premier temps de construire notre modèle. Celui-ci est basé sur les classes Ville et Route qui sont définies comme suit :

Classe Ville
CacherSélectionnez
  1. package com.abernard.zest.model; 
  2.  
  3. import java.util.ArrayList; 
  4. import java.util.List; 
  5.  
  6. /** 
  7.  * Cette classe represente une ville, c'est-a-dire une entite, ou un noeud, de  
  8.  * notre graphe. 
  9.  *  
  10.  * @author A. Bernard 
  11.  * 
  12.  */ 
  13. public class Ville { 
  14.  
  15.     /** 
  16.      * nom de la ville 
  17.      */ 
  18.     private String nom; 
  19.  
  20.     /** 
  21.      * villes auxquelles est reliee cette ville 
  22.      */ 
  23.     private List<Ville> connexions; 
  24.  
  25.     /** 
  26.      * Constructeur 
  27.      * @param n nom de la ville 
  28.      */ 
  29.     public Ville (String n) { 
  30.     this.nom = n; 
  31.     this.connexions = new ArrayList<Ville>(); 
  32.     } 
  33.  
  34.     /** 
  35.      * Ajouter une ville reliee a cette ville 
  36.      * @param v la ville a connecter 
  37.      */ 
  38.     public void addConnexion(Ville v) { 
  39.     if (!connexions.contains(v)) { 
  40. 	connexions.add(v); 
  41.     } 
  42.     } 
  43.  
  44.     /** 
  45.      * Donne la liste des villes connectees a cette ville 
  46.      * @return les villes connectees 
  47.      */ 
  48.     public List<Ville> getConnexions() { 
  49.     return this.connexions; 
  50.     } 
  51.  
  52.     /** 
  53.      * Donne le nom de cette ville 
  54.      * @return le nom de cette ville 
  55.      */ 
  56.     public String getNom() { 
  57.     return this.nom; 
  58.     } 
  59.  
  60. } 
Classe Route
CacherSélectionnez
  1. package com.abernard.zest.model; 
  2.  
  3. /** 
  4.  * Cette class represente une route, c'est-a-dire une branche du graphe. 
  5.  *  
  6.  * @author A. Bernard 
  7.  * 
  8.  */ 
  9. public class Route { 
  10.  
  11.     /** 
  12.      * la ville de depart de la route 
  13.      */ 
  14.     private Ville source; 
  15.  
  16.     /** 
  17.      * la ville d'arrivee de la route 
  18.      */ 
  19.     private Ville destination; 
  20.  
  21.     /** 
  22.      * la longueur de la route 
  23.      */ 
  24.     private int longueur; 
  25.  
  26.     /** 
  27.      * Constructeur 
  28.      * @param s la ville de depart 
  29.      * @param d la ville de destination 
  30.      * @param l la longueur de la route 
  31.      */ 
  32.     public Route(Ville s, Ville d, int l) { 
  33.     this.source = s; 
  34.     this.destination = d; 
  35.     this.longueur = l; 
  36.     } 
  37.  
  38.     /** 
  39.      * Donne la ville de depart 
  40.      * @return la ville de depart 
  41.      */ 
  42.     public Ville getSource() { 
  43.     return this.source; 
  44.     } 
  45.  
  46.     /** 
  47.      * Donne la ville d'arrivee 
  48.      * @return la ville d'arrivee 
  49.      */ 
  50.     public Ville getDestination() { 
  51.     return this.destination; 
  52.     } 
  53.  
  54.     /** 
  55.      * Donne la longueur de la route 
  56.      * @return la longueur de la route 
  57.      */ 
  58.     public int getLongueur() { 
  59.     return this.longueur; 
  60.     } 
  61.  
  62. } 

La troisième classe du modèle est un singleton, et construit le modèle de deux manières différentes. La première approche permet d'accéder à la liste de toutes les villes, qui donnent à chaque fois à quelles autres villes elles sont reliées. La deuxième approche permet d'accéder à la liste des routes, qui donnent à chaque fois la ville de départ et celle de destination.

Dans la pratique, un modèle ne permet pas toujours cette double approche. Dans notre cas c'est uniquement pour explorer les possibilités de Zest.

Classe Model
CacherSélectionnez
  1. package com.abernard.zest.model; 
  2.  
  3. import java.util.ArrayList; 
  4. import java.util.List; 
  5.  
  6. /** 
  7.  * Modele de notre graphe. Il contient toutes les villes et toutes les routes,  
  8.  * et permet d'acceder soit a la liste de toutes les villes, soit a la liste de 
  9.  *  toutes les routes 
  10.  *   
  11.  * @author A. Bernard 
  12.  */ 
  13. public enum Model { 
  14.  
  15.     /** 
  16.      * l'instance unique de notre modele 
  17.      */ 
  18.     INSTANCE; 
  19.  
  20.     /** 
  21.      * toutes les villes du graphe 
  22.      */ 
  23.     private List<Ville> villes; 
  24.  
  25.     /** 
  26.      * toutes les routes du graphe 
  27.      */ 
  28.     private List<Route> routes; 
  29.  
  30.     /** 
  31.      * Constructeur. Initialise le modele. 
  32.      */ 
  33.     private Model() { 
  34.     villes = new ArrayList<Ville>(); 
  35.     routes = new ArrayList<Route>(); 
  36.  
  37.     // Creation de toutes les villes du graphe 
  38.     Ville paris = new Ville("Paris"); 
  39.     villes.add(paris); 
  40.     Ville toulouse = new Ville("Toulouse"); 
  41.     villes.add(toulouse); 
  42.     Ville bordeaux = new Ville("Bordeaux"); 
  43.     villes.add(bordeaux); 
  44.     Ville poitiers = new Ville("Poitiers"); 
  45.     villes.add(poitiers); 
  46.     Ville metz = new Ville("Metz"); 
  47.     villes.add(metz); 
  48.  
  49.     // Creation de toutes les routes 
  50.     Route r1 = new Route(paris, toulouse, 678); 
  51.     routes.add(r1); 
  52.     paris.addConnexion(toulouse); 
  53.  
  54.     r1 = new Route(paris, poitiers, 338); 
  55.     routes.add(r1); 
  56.     poitiers.addConnexion(paris); 
  57.  
  58.     r1 = new Route(poitiers, bordeaux, 235); 
  59.     routes.add(r1); 
  60.     bordeaux.addConnexion(poitiers); 
  61.  
  62.     r1 = new Route(bordeaux, toulouse, 244); 
  63.     routes.add(r1); 
  64.     toulouse.addConnexion(bordeaux); 
  65.  
  66.     r1 = new Route(paris, metz, 333); 
  67.     routes.add(r1); 
  68.     paris.addConnexion(metz); 
  69.     } 
  70.  
  71.     /** 
  72.      * Donne la liste de toutes les villes 
  73.      * @return la liste des villes 
  74.      */ 
  75.     public List<Ville> getVilles() { 
  76.     return villes; 
  77.     } 
  78.  
  79.     /** 
  80.      * Donne la liste de toutes les routes 
  81.      * @return la liste des routes 
  82.      */ 
  83.     public List<Route> getRoutes() { 
  84.     return routes; 
  85.     } 
  86. } 

Notre modèle étant mis en place, nous pouvons maintenant créer nos graphes.

III-B. Approche orientée « nœuds »

Pour construire un graphe à partir des nœuds, Zest fournit l'interface « IGraphEntityContentProvider ». Créez la classe « EntityContentProvider » définie comme suit :

EntityContentProvider.java
CacherSélectionnez
  1. package 
  2.       com.abernard.zest.viewer; 
  3.  
  4. import java.util.List; 
  5.  
  6. import org.eclipse.jface.viewers.Viewer; 
  7. import org.eclipse.zest.core.viewers.IGraphEntityContentProvider; 
  8.  
  9. import com.abernard.zest.model.Ville; 
  10.  
  11. /** 
  12.  * ContentProvider de notre graphe. Cette implementation prend en donnees  
  13.  * d'entree la liste des villes. 
  14.  *  
  15.  * @author A. Bernard 
  16.  */ 
  17. public class EntityContentProvider implements IGraphEntityContentProvider { 
  18.  
  19.  
  20.     @SuppressWarnings("unchecked") 
  21.     @Override 
  22.     public Object[] getElements(Object input) { 
  23.     // Cette methode definit les elements d'entree du graphe. 
  24.     // Dans notre cas ce doit etre une liste de Villes. 
  25.     return ((List<Ville>)input).toArray(); 
  26.     } 
  27.  
  28.     @Override 
  29.     public void dispose() { 
  30.     //  
  31.     } 
  32.  
  33.     @Override 
  34.     public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { 
  35.     //  
  36.     } 
  37.  
  38.     @Override 
  39.     public Object[] getConnectedTo(Object entity) { 
  40.     // Pour chaque ville, on retourne la liste des villes connectees a la  
  41.     // ville courante 
  42.     if (entity instanceof Ville) { 
  43. 	return ((Ville)entity).getConnexions().toArray(); 
  44.     } else { 
  45. 	return null; 
  46.     } 
  47.     } 
  48. } 

Comme tout viewer JFace, il nous faut aussi définir un « LabelProvider ». Dans un premier temps, nos LabelProvider se contenteront d'étendre la classe « LabelProvider » de JFace. Nous verrons dans le cours « Compléments sur Zest » que l'on peut définir bien d'autres choses grâce à des interfaces particulières. Créez donc la classe « EntityLabelProvider » :

EntityLabelProvider.java
CacherSélectionnez
  1. package 
  2.       com.abernard.zest.viewer; 
  3.  
  4. import org.eclipse.jface.viewers.LabelProvider; 
  5.  
  6. import com.abernard.zest.model.Route; 
  7. import com.abernard.zest.model.Ville; 
  8.  
  9. /** 
  10.  * LabelProvider du graphe. Determine le texte a afficher selon le type  
  11.  * d'element. 
  12.  *  
  13.  * @author A. Bernard 
  14.  */ 
  15. public class EntityLabelProvider extends LabelProvider { 
  16.  
  17.     @Override 
  18.     public String getText(Object element) { 
  19.     // On retourne la longueur de la route, ou le nom de la ville 
  20.     // On remarquera que le texte sur la route n'est jamais affiche :  
  21.     // aucun element de type Route n'est traite. 
  22.     if (element instanceof Route) { 
  23. 	return ((Route)element).getLongueur() + "km"; 
  24.     } else if (element instanceof Ville) { 
  25. 	return ((Ville)element).getNom(); 
  26.     } else { 
  27. 	return null; 
  28.     } 
  29.     } 
  30.  
  31. } 

Créez maintenant la vue « LinkGraphView », qui affichera un graphe « orienté nœuds ». Les données d'entrée du graphe sont données via la méthode « setInput », et sont donc les villes de notre modèle.

EntityGraphView.java
CacherSélectionnez
  1. package com.abernard.zest; 
  2.  
  3. import org.eclipse.swt.SWT; 
  4. import org.eclipse.swt.widgets.Composite; 
  5. import org.eclipse.ui.part.ViewPart; 
  6. import org.eclipse.zest.core.viewers.GraphViewer; 
  7. import org.eclipse.zest.layouts.LayoutStyles; 
  8. import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; 
  9.  
  10. import com.abernard.zest.model.Model; 
  11. import com.abernard.zest.viewer.EntityContentProvider; 
  12. import com.abernard.zest.viewer.EntityLabelProvider; 
  13.  
  14. /** 
  15.  * Cette vue affiche un graphe construit a partir d'un modele base sur les  
  16.  * noeuds du graphe (dans notre cas les villes). 
  17.  *  
  18.  * @author A. Bernard 
  19.  */ 
  20. public class EntityGraphView extends ViewPart { 
  21.  
  22.     /** 
  23.      * le graphe 
  24.      */ 
  25.     private GraphViewer viewer; 
  26.  
  27.     @Override 
  28.     public void createPartControl(Composite parent) { 
  29.     viewer = new GraphViewer(parent, SWT.NONE); 
  30.     // Traitement du contenu 
  31.     viewer.setContentProvider(new EntityContentProvider()); 
  32.     // Traitement de l'affichage 
  33.     viewer.setLabelProvider(new EntityLabelProvider()); 
  34.  
  35.     // Donnees d'entree du graphe 
  36.     // Comme pour les autres viewers JFace, la methode setInput doit etre  
  37.     // appelee APRES la definition des ContentProvider et LabelProvider. 
  38.     viewer.setInput(Model.INSTANCE.getVilles()); 
  39.  
  40.     // Definition du layout 
  41.     viewer.setLayoutAlgorithm(new 
  42.       SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING)); 
  43.     viewer.applyLayout(); 
  44.  
  45.     } 
  46.  
  47.     @Override 
  48.     public void setFocus() { 
  49.     //  
  50.     } 
  51. } 

Le graphe est donc construit correctement, et ceci de manière très simple. On constate une chose : même si le LabelProvider fournit le texte à afficher pour des éléments de type « Route », aucun texte n'est affiché. On le verra par la suite, le fonctionnement est différent dans une approche orientée « branches ».

Image non disponible

III-C. Approche orientée « branches »

Construisons maintenant notre graphe à partir des liens entre nœuds. Pour cela, Zest met à notre disposition l'interface « IGraphContentProvider ». Créez la classe « LinkContentProvider » comme suit :

LinkContentProvider.java
CacherSélectionnez
  1. package 
  2.       com.abernard.zest.viewer; 
  3.  
  4. import java.util.ArrayList; 
  5.  
  6. import org.eclipse.jface.viewers.Viewer; 
  7. import org.eclipse.zest.core.viewers.IGraphContentProvider; 
  8.  
  9. import com.abernard.zest.model.Route; 
  10.  
  11. /** 
  12.  * ContentProvider de notre graphe. Cette implementation prend en donnees  
  13.  * d'entree la liste des routes. 
  14.  *  
  15.  * @author A. Bernard 
  16.  */ 
  17. public class LinkContentProvider implements IGraphContentProvider { 
  18.  
  19.     @Override 
  20.     public void dispose() { 
  21.     // 
  22.     } 
  23.  
  24.     @Override 
  25.     public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { 
  26.     //  
  27.     } 
  28.  
  29.     @Override 
  30.     public Object getSource(Object rel) { 
  31.     // Donne pour chaque branche du graphe le noeud source de la branche 
  32.     if (rel instanceof Route) { 
  33. 	return ((Route)rel).getSource(); 
  34.     } else { 
  35. 	return null; 
  36.     } 
  37.     } 
  38.  
  39.     @Override 
  40.     public Object getDestination(Object rel) { 
  41.     // Donne pour chaque branche du graphe le noeud destination de la 
  42.       branche 
  43.     if (rel instanceof Route) { 
  44. 	return ((Route)rel).getDestination(); 
  45.     } else { 
  46. 	return null; 
  47.     } 
  48.     } 
  49.  
  50.     @SuppressWarnings("unchecked") 
  51.     @Override 
  52.     public Object[] getElements(Object input) { 
  53.     // Ici, les donnees d'entree du graphe sont les routes du modele, c'est- 
  54.     // a-dire les branches du graphe. 
  55.     return ((ArrayList<Route>)input).toArray(); 
  56.     } 
  57.  
  58.  
  59.  
  60. } 

Là aussi, nous devons définir un LabelProvider. Notez que dans ce cas présent, nous pourrions réutiliser celui que nous avions défini dans la partie précédente. Cependant, en prévision du cours suivant, je vous invite à créer la classe « LinkLabelProvider » :

LinkLabelProvider.java
CacherSélectionnez
  1. package 
  2.       com.abernard.zest.viewer; 
  3.  
  4. import org.eclipse.jface.viewers.LabelProvider; 
  5.  
  6. import com.abernard.zest.model.Route; 
  7. import com.abernard.zest.model.Ville; 
  8.  
  9. /** 
  10.  * LabelProvider du graphe. Determine le texte a afficher selon le type  
  11.  * d'element. 
  12.  *  
  13.  * @author A. Bernard 
  14.  */ 
  15. public class LinkLabelProvider extends LabelProvider { 
  16.  
  17.     @Override 
  18.     public String getText(Object element) { 
  19.     // On retourne la longueur de la route, ou le nom de la ville 
  20.     // Dans ce cas, les textes sont affiches sur tous les elements du graphe 
  21.     if (element instanceof Route) { 
  22. 	return ((Route)element).getLongueur() + "km"; 
  23.     } else if (element instanceof Ville) { 
  24. 	return ((Ville)element).getNom(); 
  25.     } else { 
  26. 	return null; 
  27.     } 
  28.     } 
  29.  
  30. } 

Enfin, nous pouvons créer la vue qui va afficher le graphe :

LinkGraphView.java
CacherSélectionnez
  1. package com.abernard.zest; 
  2.  
  3. import org.eclipse.swt.SWT; 
  4. import org.eclipse.swt.widgets.Composite; 
  5. import org.eclipse.ui.part.ViewPart; 
  6. import org.eclipse.zest.core.viewers.GraphViewer; 
  7. import org.eclipse.zest.layouts.LayoutStyles; 
  8. import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; 
  9.  
  10. import com.abernard.zest.model.Model; 
  11. import com.abernard.zest.viewer.LinkContentProvider; 
  12. import com.abernard.zest.viewer.LinkLabelProvider; 
  13.  
  14. /** 
  15.  * Cette vue affiche un graphe construit a partir d'un modele base sur les  
  16.  * branches du graphe (dans notre cas les routes). 
  17.  *  
  18.  * @author A. Bernard 
  19.  */ 
  20. public class LinkGraphView extends ViewPart { 
  21.  
  22.     /** 
  23.      * le graphe 
  24.      */ 
  25.     private GraphViewer viewer; 
  26.  
  27.     @Override 
  28.     public void createPartControl(Composite parent) { 
  29.     viewer = new GraphViewer(parent, SWT.NONE); 
  30.     // Traitement du contenu 
  31.     viewer.setContentProvider(new LinkContentProvider()); 
  32.     // Traitement de l'affichage 
  33.     viewer.setLabelProvider(new LinkLabelProvider()); 
  34.  
  35.     // Donnees d'entree du graphe 
  36.     // Comme pour les autres viewers JFace, la methode setInput doit etre  
  37.     // appelee APRES la definition des ContentProvider et LabelProvider. 
  38.     viewer.setInput(Model.INSTANCE.getRoutes()); 
  39.  
  40.     // Definition du layout 
  41.     viewer.setLayoutAlgorithm(new 
  42.       SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING)); 
  43.     viewer.applyLayout(); 
  44.  
  45.     } 
  46.  
  47.     @Override 
  48.     public void setFocus() { 
  49.     //  
  50.     } 
  51. } 

Dans le cas présent, le texte sur les routes est affiché, ainsi que celui sur les villes.

Image non disponible

IV. Conclusion

Dans ce tutoriel nous avons appris comment afficher un graphe, soit sans modèle de données associé, soit depuis un modèle en utilisant des concepts classiques de JFace et donc aisés à mettre en place. Notre graphe est pour l'instant basique, mais les possibilités d'amélioration sont nombreuses et ce sont ces possibilités que je vous montrerai dans la deuxième partie de ce cours sur Zest : « Compléments sur Zest ».

V. Liens utiles

VI. Remerciements

Je tiens à remercier pour cet article Mickaël BARON, qui m'a poussé à me lancer dans la rédaction d'articles sur developpez.com, ainsi que les membres de la communauté Java pour leurs remarques et leurs conseils. Enfin, un grand merci à Claude Leloup et Maxime Gault pour leur relecture attentive.