TP Éditeur de dessin en Swing

Introduction

Cet exercice a pour but de permettre une prise en main des API AWT et Swing de Java. Il n'est donc ici pas encore question d'utiliser un modèle d'architecture logicielle pour la conception de cette IHM mais simplement de manipuler les mécanismes de base des composants d'interfaces ainsi que les gestionnaires d'événements.

La version 1.0 de l'éditeur

Dessiner des rectangles jaunes sur fond cyan

  • Réaliser un éditeur de dessin minimaliste, qui permette de dessiner des rectangles d'une couleur donnée (jaune) à l'aide de la souris, dans une zone de dessin (un JPanel) de couleur cyan. Il faut absolument donner une représentation continue du rectangle lors de l'interaction, c'est-à-dire le dessiner lors du déplacement de la souris bouton appuyé et non pas seulement lors du relâchement du bouton.

  • Pour cela, il faut créer un composant Editeur (dérivé de JFrame) dans lequel on place un composant ZoneDeDessin (dérivé de JPanel) auquel on aura associé des gestionnaires d'événements (implémentant MouseListener et MouseMotionListener ou bien dérivés de MouseAdapter et MouseMotionAdapter).

  • Dans cette toute première phase, on ne crée pas d'objets graphiques : il faut simplement redéfinir la méthode paint de ZoneDeDessin de façon à ce qu'elle dessine un contour rectangulaire lors du déplacement de la souris, et que ce rectangle reste visible après le relâchement du bouton de la souris. Il faudra au préalable avoir mémorisé le point de départ de l'interaction au moment où l'on a appuyé sur le bouton de la souris.

  • Noter que si l'on n'appelle pas la méthode paint de l'ancêtre, on aura des problèmes pour afficher par la suite, et on a déjà un manque au niveau de la couleur du fond de la ZoneDeDessin.

  • Vérifier que le dessin reste bien en place lorsque la fenêtre subit des modifications.

  • Remarque : on n'affiche jamais plus d'un dessin à la fois avec cette version de l'éditeur

Créer de vrais objets dessins et les déplacer

  • Créer de vrais objets Dessin(s) (héritiers de JPanel) au début de chaque interaction de dessin.

    • Il faudra alors les ajouter dans la ZoneDeDessin, au bon emplacement et avec une taille nulle.

    • Ensuite, en cours d'interaction, on changera la taille du dessin et si besoin son emplacement.

      • A ce niveau, on se contentera d'un Dessin rectangulaire à qui on aura donné une couleur de fond jaune.

  • On veut déplacer (toujours à l'aide de la souris) les dessins que l'on a créés.

    • Associer à ces objets les Listeners adéquats (MouseListener et MouseMotionListener) pour traiter leur déplacement dans la ZoneDeDessin à l'aide de la souris; en utilisant les méthodes adaptées : mousePressed et mouseDragged.

Modifier le layout manager de ZoneDeDessin

  • Constater que lorsqu'on redimensionne la ZoneDeDessin (en redimensionnant l'Editeur par exemple) les instances de Dessin sont toutes alignées et de même taille : c'est l'effet du FlowLayout qui est associé par défaut à un JPanel et qui utilise de plus la "preferredSize" des objets à réorganiser, et dont la valeur par défaut est petite.

  • On remédie à ce problème en supprimant le layout manager de ZoneDeDessin (on lui donne null comme layout manager).

La version 2.0 de l'éditeur

Dessiner de nouveaux types d'objets

  • Offrir maintenant, via des actions sur des boutons, la possibilité de créer plusieurs types de dessins (rectangles, ellipses, ...). La caractéristique commune de tous ces dessins sera qu'ils peuvent s'inscrire dans un rectangle.

  • Il va donc maintenant falloir créer plusieurs classes d'objets graphiques, pour lesquelles on redéfinira la méthode paint de façon à obtenir le résultat visuel souhaité (il faudra dessiner dans le repère local de l'objet graphique !).

  • Il faudra également redéfinir la méthode contains de ces classes de façon à s'adapter d'une part aux nouvelles formes de ces objets, et d'autre part au fait que certains de ces objets sont creux et donc qu'il ne faudrait pouvoir les saisir qu'en cliquant sur leur contour.

  • Il est souhaitable (en fait il est indispensable), pour une meilleure décomposition objet et pour une plus grande facilité d'évolution de l'éditeur, de ne pas faire de ``switch'' ni de successions de tests imbriqués pour déterminer quel type de dessin doit être réalisé en cours d'interaction : on préférera avoir recours à une classe permettant de créer le bon type d'objet graphique (utilisation d'un patron de conception State).

  • L'utilisateur doit être informé du type de dessin en cours (utiliser par exemple des JRadioButton(s)).

Pouvoir choisir la couleur des objets à dessiner

  • Offrir également la possibilité de choisir une couleur à utiliser pour les (prochains) dessins.

  • Il faudra en tenir compte pour les dessins intermédiaires et les créations d'objets graphiques.

  • L'utilisateur doit être informé du type de la couleur en cours :

    • utiliser ici des JCheckBox(es), ``vus'' comme des JRadioButton(s) (même si, d'un point de vue sémantique, ce n'est pas l'usage habituel des cases à cocher...) ;

    • visualiser cette couleur dans une zone appropriée : utiliser ici un patron de conception Observateur pour être prévenu de tout changement de couleur de dessin.

      • Il sera possible ici d'utiliser l'attribut foreground de la zone de dessin pour stocker la couleur des dessins à créer, et profiter ainsi de la propagation des changements de valeurs de cet attribut vers les abonnés à ces changements, puisque les composants Swing sont construits selon le modèle des java beans.

Pouvoir réordonner visuellement les dessin

  • Permettre à l'utilisateur d'éloigner ou de rapprocher les dessins (sur le plan de la profondeur : méthode setComponentZOrder) vie l'utilisation de la molette de la souris :

    • ajouter pour cela à chaque dessin créé un MouseWheelListener et utiliser sa méthode MouseWheelMoved.

Accéder de plusieurs façons aux fonctionnalités

  • Offrir également l'accès aux fonctionnalités (choix du type de dessin et de la couleur) via des menus déroulants accessibles depuis une barre de menu (JMenuBar, JMenu et par exemple JRadioButtonMenuItem ou JCheckBoxMenuItem). Il sera possible de profiter ici de l'architecture MVC des composants Swing et d'utiliser le partage de modèles entre composants.

  • Il faudra que les items des menus et les boutons soient dans un état cohérent.

  • Associer des raccourcis clavier à certaines fonctionnalités.

Visualiser les objets créés dans l'éditeur

  • Ajouter un composant permettant de lister les objets qui ont été créés par l'utilisateur :

    • dans un premier temps ce composant ne sera pas interactif, mais il présentera de façon dynamique les dessins dans leur ordre de création ;

    • dans un second temps il faudra faire évoluer dynamiquement cet afficheur suite à des changements de "profondeur" appliqués sur les dessins à l'aide de la molette de la souris comme proposé précédemment.

  • Ajouter des interactions dans cet afficheur pour permettre d'agir sur les dessins :

    • les déplacer dans la liste pour les réordonner,

    • mettre en évidence dans l'éditeur un dessin sélectionné via cet afficheur,

    • ...

Offrir plusieurs modes de fonctionnement de l'éditeur

  • Permettre à l'utilisateur de déterminer quelle est l'action par défaut applicable sur un dessin, par exemple le déplacer, l'éloigner ou le rapprocher, le détruire, le redimensionner, ou encore ne rien faire (c'est-à-dire autoriser de commencer un nouveau dessin en cliquant au dessus d'un dessin existant). Il faudra pour cela parcourir les dessins de l'éditeur et leur appliquer des changements de listeners...

Donner toujours plus d'informations à l'utilisateur

  • Insérer des ToolTip(s) là où c'est possible pour donner un maximum d'informations à l'utilisateur.

  • Modifier l'indicateur de couleur (celui qui observe les changements de foreground de la zone de dessin) de façon à ce qu'il observe aussi les changements de créateur de dessins, et pourquoi pas aussi ses changements de background : il faut alors le faire réagir à ces changements en affichant un dessin de la bonne forme, avec la bonne couleur, sur le bon fond.