Browse Source

TP 7 à 9

arnaud.lewandowski@univ-littoral.fr 2 months ago
parent
commit
a81d67ed8d
8 changed files with 194 additions and 2 deletions
  1. 3 0
      README.md
  2. 1 1
      docs/TP1.md
  3. 1 1
      docs/TP4.md
  4. 29 0
      docs/TP5.md
  5. 39 0
      docs/TP7.md
  6. 64 0
      docs/TP8.md
  7. 57 0
      docs/TP9.md
  8. BIN
      docs/images/minipaint_09.png

+ 3 - 0
README.md

@@ -8,3 +8,6 @@ Cette application en JavaFX, permettant de dessiner des formes géométriques, v
 - [TP4 – On continue...](docs/TP4.md)
 - [TP5 – Groupement de formes](docs/TP5.md)
 - [TP6 – Le patron Command](docs/TP6.md)
+- [TP7 – Améliorations](docs/TP7.md)
+- [TP8 – Le retour de l'Observer](docs/TP8.md)
+- [TP9 – Changement de stratégie](docs/TP9.md)

+ 1 - 1
docs/TP1.md

@@ -4,7 +4,7 @@
 Dans cette première partie, nous allons nous familiariser avec le code de l’application, et en profiter pour découvrir un ou deux patrons de conception. 
 
 
-### 🔬 À la recherche des classes perdues...
+### 🗺 À la recherche des classes perdues...
 ---
 D’abord, importez le projet sous IntelliJ, Eclipse, ou un autre environnement de développement de votre choix. 
 Les dépendances du projet sont gérées automatiquement grâce à Maven. Par curiosité, vous pouvez les identifier dans le fichier `pom.xml` :

+ 1 - 1
docs/TP4.md

@@ -35,7 +35,7 @@ Grâce à la sélection multiple, on peut donc appliquer des actions sur toutes
 
 >**🖥 TODO**
 >
-> - Corrigez cela… 🩹
+> - Corrigez cela… 
 
 <br> 
 

+ 29 - 0
docs/TP5.md

@@ -14,4 +14,33 @@ Même s’il est possible de déplacer plusieurs formes à la fois (grâce à la
 
 <br>
 
+### 🎀 Quelques améliorations
+---
+Vous avez sans doute remarqué qu'il reste quelques fonctionnements disgracieux : par exemple, si on souhaite créer une forme, et que le point de départ se trouve sur une forme déjà existante, celle-ci est déplacée en même temps que l'autre est créée. 
+
+>**🖥 TODO**
+>
+> - Faites en sorte que le déplacement soit désactivé lorsqu'une forme est en train d'être créée.
+
+<br>
+
+Une autre fonction intéressante serait de pouvoir mettre une forme au premier plan (devant les autres).
+
+>**🖥 TODO**
+>
+> - Implémentez cette fonctionnalité
+
+<br>
+
+#### 🏆 Bonus
+
+>**🖥 TODO**
+>
+> - On voudrait aussi pouvoir sélectionner plusieurs formes en délimitant une "zone" de sélection avec la souris (par un clic-drag-release)
+
+
+
+<br>
+
+
 [🔙 Retour](../README.md)

+ 39 - 0
docs/TP7.md

@@ -0,0 +1,39 @@
+# Minipaint 
+## TP7 – Améliorations
+
+### 🧬 Dupliquer une forme
+---
+On aimerait pouvoir dupliquer facilement la ou les formes sélectionnées. 
+
+>**🖥 TODO**
+>
+> - Identifiez le patron de création qui semble correspondre à ce besoin. 
+> - Implémentez le code nécessaire.
+
+<br>
+
+### 📝 Ajouter du texte sur une forme
+---
+On voudrait pouvoir ajouter du texte sur une forme sélectionnée. On ne veut pas en faire un attribut de la classe `ShapeAdapter`, car en général, seulement quelques formes seront concernées : inutile de « polluer » la classe avec cela. 
+
+Nous allons pour cela utiliser le patron *Décorateur* (lien vers la [vidéo qui en parle](https://www.youtube.com/watch?v=GCraGHx6gso&t=140s)). Ce patron permet d’ajouter de manière dynamique des informations sur certains objets. 
+
+
+>**🖥 TODO**
+>
+> - Etudiez le fonctionnement du patron, identifiez les classes concernées dans l’application, et faites les changements nécessaires. 
+> - On pourra ajouter un bouton dans la Toolbar permettant d’ajouter du texte sur la (ou les) forme(s) sélectionnée(s).
+
+<br> 
+
+### 🚧 Gestion des exceptions
+---
+>**🖥 TODO**
+>
+> - Si on cherche à ajouter du texte sur un groupe de formes, une exception doit être levée au niveau du décorateur. Cette exception sera capturée par la commande qui est à l’origine de l’action, et un message d’erreur doit être affiché. Si une commande provoque une exception, elle ne doit pas être ajoutée à la pile de commandes (l'historique pour le undo/redo).
+> - Étendre ce mécanisme d’exception à toutes les commandes. Si une commande rencontre une erreur (par exemple si aucune forme n’est sélectionnée), alors une exception doit être levée, et la commande ne sera pas ajoutée à l’historique. 
+> - Les messages d’erreur des exceptions seront affichés dans une nouvelle barre de statut.
+
+<br>
+
+[🔙 Retour](../README.md)

+ 64 - 0
docs/TP8.md

@@ -0,0 +1,64 @@
+# Minipaint 
+## TP8 – Le retour de l'Observer 
+
+### 💥 Encore de l’observer 
+---
+On l’aime vraiment bien, ce patron… En fait, il est tellement utile qu’on le retrouve partout, implémenté dans chaque recoin des API. Prenons encore un exemple. 
+
+Reprenons la fonctionnalité permettant d’ajouter du texte à une forme. Pour cela, dans le décorateur, on a ajouté un objet de type `Text` qui contient la chaine de caractères. On l’a positionné comme on a pu, et ensuite on a veillé à bien le déplacer en même temps que la forme lors des appels à la méthode offset.
+
+C’est bien, mais on aurait pu utiliser une fonctionnalité de l’API `javafx` qui est basée sur le patron *observer* : c’est la notion de *Binding*. En gros, cela permet de lier un attribut d’un objet à une propriété d’un autre objet. C’est-à-dire que la valeur du premier attribut sera automatiquement mise à jour lorsque l’autre attribut sera modifié. 
+
+Voyons comment utiliser cela. Tout d’abord, les propriétés qu’on veut « écouter » sont celles qui sont relatives au déplacement de la forme de base. 
+
+>**🖥 TODO**
+>
+> - On va les rendre accessibles en ajoutant deux méthodes à l’interface `IShape` :
+>
+		public ObservableValue translateXProperty();
+		public ObservableValue translateYProperty();
+	
+> - On va commencer par implémenter ces méthodes uniquement dans la classe `ShapeAdapter`. L’implémentation consiste simplement à retourner le résultat de l’appel à `translateXProperty()` et `translateYProperty()` sur l’objet interne de type Shape.
+
+<br> 
+
+Maintenant, cela veut dire qu’on peut « écouter » les propriétés `translateX` et `translateY`. 
+
+>**🖥 TODO**
+>
+> - Il ne reste plus qu’à connecter les propriétés correspondantes de l’objet `Text` du décorateur sur ces propriétés (c’est le « *binding* »). Dans le décorateur, lors de l’instanciation de l’objet `Text` : appelez sur l’objet `Text` les méthodes `translateXProperty().bind()` et `translateYProperty().bind()`, en passant en paramètre les appels aux deux méthodes écrites précédemment. 
+> - N’oubliez pas de supprimer l’ancien code qui permettait de déplacer l’objet de type `Text` dans la méthode `offset`. 
+
+Admirez le résultat.🥲
+
+#### 🍹 Amélioration
+En fait, lors du « *binding* », plutôt que de se référer aux `translateX/Y`, il serait plus intéressant d’obtenir directement les coordonnées du centre de la forme, autrement dit la valeur du `translateX` (ou `translateY`) + les coordonnées du centre de la forme au moment de sa création. Ainsi, on n’aurait même plus à initialiser les coordonnés du centre de l’objet `Text` : le *binding* seul suffira.
+
+>**🖥 TODO**
+>
+> - Modifiez les méthodes `translateXProperty()` et `translateYProperty()` pour y ajouter les coordonnées X et Y du centre de la forme. 
+> - Renommez ces méthodes pour que leur nom reflète mieux l'information qu'elles retournent.
+
+<br>
+
+### 🪡 Relier des formes
+---
+Cette fonction très utile va beaucoup simplifier le développement d’une nouvelle fonctionnalité : relier des formes entre elles par un trait. 
+
+>**🖥 TODO**
+>
+> - Commencer par écrire une nouvelle classe `Edge`, qui hérite de `IShape`, et qui possède trois attributs : `from` et `to` de type `IShape`, et `shape` de type `Line`.
+> - La classe aura un constructeur à 2 paramètres de type `IShape`, qui seront les 2 formes à relier. Lors de l’instanciation, le paramètre `shape` sera créé (une nouvelle instance de `Line`). Les coordonnées du point de départ et du point d’arrivée de cette ligne seront liées (avec un « *binding* ») aux propriétés des formes `from` et `to` (grâce aux méthodes écrites précédemment).
+
+NB : Un objet de type `Edge` peut être sélectionné, mais ne peut pas être déplacé. 
+
+>**🖥 TODO**
+>
+> - Créer une *Commande* permettant de relier par un trait les 2 formes sélectionnées (on vérifiera qu’il y a bien 2 formes sélectionnées). Il faudra donc créer une nouvelle instance de `Edge`, et l’ajouter à la liste des `shapes` du `DrawingPane`. 
+
+#### 🏆 Bonus
+En implémentant les méthodes `translateXProperty()` et `translateYProperty()` de la classe `Edge`, de telle sorte qu’elles retournent le *Binding* correspondant aux coordonnées du milieu du segment, alors on peut ajouter du texte sur une ligne, ou même relier des lignes entre elles !
+
+<br>
+
+[🔙 Retour](../README.md)

+ 57 - 0
docs/TP9.md

@@ -0,0 +1,57 @@
+# Minipaint 
+## TP9 – Changement de stratégie
+
+### 🎸 The Edge : la suite
+--- 
+On voudrait pouvoir dessiner plusieurs sortes de traits (droits, courbes, orthogonaux, etc), et être capable de changer dynamiquement le type d’un trait. 
+
+>**🖥 TODO**
+>
+> - Expliquer pourquoi étendre la classe `Edge` avec plusieurs sous-classes (une par type de trait) ne serait pas une bonne solution.
+
+
+
+Dans la classe `Edge`, on va commencer par remplacer le type `Line` (utilisé pour dessiner un trait) par le type `Path`. 
+
+>**🖥 TODO**
+>
+> - Faites les modifications nécessaires. 
+
+Maintenant, pour pouvoir gérer plusieurs sortes de trait, on va utiliser le patron *Strategy*. On aura une stratégie par type de trait. Chaque stratégie sera dédiée à construire un `Path`. Documentez-vous sur ce patron pour comprendre son fonctionnement (une [petite vidéo](https://www.youtube.com/watch?v=v9ejT8FO-7I&t=15s) 📺 ?)
+
+L’interface `IEdgeStrategy` aura une seule méthode :  
+
+	void buildPath(IShape from, IShape to, Path path);
+
+Chaque stratégie implémentera cette méthode en vidant les éléments du path passé en paramètre, et en le remplissant avec les éléments correspondant au calcul du nouveau trait. 
+
+Une stratégie sera passée en paramètre du constructeur de la classe `Edge`, et il sera aussi possible d’en changer grâce à une méthode `setEdgeStrategy(IEdgeStrategy strategy)`. Lorsqu’une nouvelle stratégie sera appliquée à un `Edge`, alors on recalculera par la même occasion le `path` correspondant. 
+
+>**🖥 TODO**
+>
+> - Commencez à implémenter une stratégie simple, qui consistera à simplement tracer un trait droit entre les deux formes. 
+> - Implémentez une deuxième stratégie, permettant de tracer une liaison orthogonale entre 2 formes sélectionnées. 
+> - Créer une commande qui permet d’appliquer une stratégie donnée aux objets de type `Edge` sélectionnés (la stratégie sera passée en paramètre du constructeur de la commande). 
+> - Dans la `ToolBar`, on va rajouter un objet de type `ComboBox` qui contiendra la liste des stratégies possibles. Lorsqu’on va sélectionner une stratégie, elle sera appliquée à tous les objets de type `Edge` qui sont sélectionnés, grâce à l’exécution de la commande correspondante. 
+
+Évidemment, quelques ajustements sont nécessaires pour pouvoir récupérer le « milieu » du trait (grâce aux méthodes `centerXProperty` et `centerYProperty`). En effet, ces informations dépendent du type de trait. 
+
+>**🖥 TODO**
+>
+> - On va donc ajouter deux méthodes à l’interface `IEdgeStrategy` :
+>
+		public ObservableValue middleXProperty();
+		public ObservableValue middleYProperty();
+
+> - On fera appel à ces méthodes dans la classe `Edge`.  
+
+#### 🛵 Un peu plus loin…
+>**🖥 TODO**
+>
+> - Si une seule forme est sélectionnée, alors on doit pouvoir dessiner un lien sur la forme elle-même. 
+
+![](images/minipaint_09.png)
+
+<br>
+
+[🔙 Retour](../README.md)

BIN
docs/images/minipaint_09.png