~ / TIS3 / AL / tps / 2-separable-model /

Modèle séparable avec Java/Swing

© 2007—2018 - Renaud Blanch

Le but de ce TP est de comprendre l'utilisation des modèles de la boîte à outils Swing de Java. Vous allez réaliser une vue multiple sur une même donnée : la liste des fonctions affichées par le grapher. On veut afficher la même données sous deux formes : dans une liste JList avec le nom des fonctions et dans un affichage graphique avec des courbes.

C’est une mauvaise pratique de gérer la liste à afficher à deux endroits différents car à chaque fois on doit tout gérer en double (ajout dans la liste, suppression, …) On va donc utiliser une seule instance de la liste contenant les fonctions à afficher et passer cette instance au grapher et à la JList. Ainsi le grapher et la JList vont partager le même modèle de données.

Squelette d'application

Récupérez les sources du squelette de l'application. Celles-ci fournissent dans le répertoire graphser/src/packages : grapher.fc et grapher.ui (respectivement le noyau fonctionnel et l'interface graphique de notre programme). Explorez le code pour comprendre ce qu'il fait. Ce code vous offre aussi une correction du TP précédent (machine à état dans grapher.ui.Interaction).

Créez un nouveau projet nommé GrapherModel à partir de ces sources (New Java Project with Existing Sources) en ajoutant le répertoire téléchargé grapher/src à ce projet. Exécutez la classe principale grapher.ui.Main de ce projet pour vérifier que le code fonctionne bien. En particulier, la bare de menu propose un menu "Expression" avec une entrée "Add…" qui permet d'ajouter une fonction au grapher. Celle-ci est alors affichée dans le grapher, mais pas encore dans la liste qui est présente à droite du grapher.

Modèle séparable de liste

Faire en sorte que le grapher et la liste partagent le même modèle est le but de ce TP.

Il s'agit tout d'abord de faire en sorte que le grapher utilise une liste de fonctions qui puisse être mise en commun avec la JList. Il s'agit donc de modifier, la classe Grapher pour qu'elle utilise pour son attribut functions (qui stocke les fonctions) un DefaultListModel plutôt qu'un Vector. Modifiez la class Grapher en conséquence. Vérifiez que votre code fonctionne toujours.

On va gérer le DefaultListModel (sa création et sa mise à jour) dans le Main désormais. A partir de ce modèle, on crée une JList. Passez la JList en paramètre au grapher lorsqu'il est construit, et faites en sorte que le grapher partage son modèle avec celle-ci (on pourrait aussi passer le modèle directement au grapher, mais à la question suivante, le grapher aura besoin de la JList).

Vérifiez maintenant que lorsque vous ajoutez une fonction, elle apparaît des deux côtés. Pour cela, il faudra penser à appeler la méthode repaint du grapher au moment de l'ajout.

Faites en sorte que les fonctions sélectionnées par l'utilisateur dans la liste (JList.isSelectedIndex) apparaissent avec un trait épais sur le grapher (Graphics2D.setStroke et BasicStroke). Pour que l'affichage soit mis à jour quand la sélection change, il faudra une fois encore appeler repaint quand celle-ci change, et pour cela s'abonner aux changements de sélection de la JList (JList.addListSelectionListener). Vérifier que le reste du graphe s'affiche toujours normalement et que l'affichage en gras se fait en temps réel.

Pour aller plus loin

Ajoutez la possibilité de supprimer les fonctions sélectionnées dans la liste en ajoutant une commande "Remove" dans le menu "Expression" et un raccourci clavier. Vérifier que la suppression fonctionne bien et apparaît en temps réel. Vous pouvez tester en supprimant la première fonction de la liste, la dernière, en supprimant plusieurs fonctions en même temps (sélection multiple en maintenant le touche Ctrl enfoncée), …

mise à jour : 16 mars 2021