Flame Maker – Etape 9 - Interface de modification des poids
Introduction
Le but de cette étape est de terminer le programme Flame Maker en ajoutant la partie manquante de l'interface utilisateur, à savoir celle permettant la visualisation et l'édition des poids des variations.
A la fin de cette étape, l'interface de votre programme devrait ressembler à la copie d'écran ci-dessous.
L'interface graphique finale
Interface de modification des poids
L'interface permettant la visualisation et la modification des poids des six variations de la transformation Flame actuellement sélectionnée est composée de six champs textuels formatés et six étiquettes associées. Ces différents éléments sont à placer dans un panneau séparé, qui est le second fils du panneau d'édition de la transformation Flame sélectionnée, créé lors de l'étape 7. La hiérarchie des conteneurs finale étant quasiment identique à celle de cette étape, elle n'est pas répétée ici.
En examinant attentivement la copie d'écran plus haut, on constate qu'une fine ligne sépare le panneau contenant l'interface de modification affine et le panneau des poids. Cette ligne est un séparateur, modélisé par la classe JSeparator
, ajouté entre les deux panneaux.
Pour placer les composants dans le panneau, il est recommandé d'utiliser à nouveau le gestionnaire GroupLayout
. Le découpage en groupes horizontaux et verticaux devrait être évident à la vue de la copie d'écran et ne sera donc pas explicité ici.
Afin que le lien entre une étiquette et le champ textuel correspondant soit clair, il faut placer, sur l'axe horizontal, de petits espacements entre chaque paire étiquette/champ. Sans cela, le label Horseshoe, par exemple, est trop proche du champ correspondant au poids de la variation Swirl et l'interface est difficile à comprendre. Avec le gestionnaire GroupLayout
, de tels espacements peuvent facilement être ajoutés aux groupes séquentiels, grâce à la méthode addPreferredGap
. Cette méthode prend un argument spécifiant le genre d'espacement à ajouter, qui doit ici être la constante ComponentPlacement.UNRELATED
. Cette valeur spécifie que l'espacement sépare des composants qui ne sont pas liés entre-eux.
Les champs textuels formatés des poids diffèrent de ceux paramétrant les transformations affines composables en deux points :
- Leur contenu doit changer lorsque la transformation Flame sélectionnée change, puisqu'il doit refléter le poids des variations de cette transformation-là. Cela implique l'ajout d'un auditeur de sélection active qui se charge de mettre à jour la totalité des champs lorsque celle-ci change.
- Tout changement de leur contenu par l'utilisateur doit provoquer un changement du poids de la variation correspondante de la transformation Flame sélectionnée. Si les observateurs ont bien été définis, ce changement provoque à son tour un redessin de la fractale.
Pour être informé des changements du contenu d'un champ textuel formaté, il faut bien entendu lui ajouter un observateur. La méthode à utiliser dans ce cas est addPropertyChangeListener
, à laquelle on doit passer la chaîne value
comme nom de propriété.1
Une fois terminé, votre programme souffrira probablement du problème suivant : lorsque la transformation Flame sélectionnée change, la fractale est redessinée, ce qui peut avoir un fâcheux impact sur ses performances. Vérifiez si votre programme souffre de ce problème, et si oui, résolvez-le de manière aussi propre que possible. S'il n'en souffre pas, demandez-vous pourquoi.
Résumé
Pour cette étape, vous devez écrire tout le code créant et gérant le panneau des poids des variations, comme décrit ci-dessus.
Comme pour l'étape précédente, il est important de bien factoriser le code pour éviter la duplication. En particulier, la création des six étiquettes, des champs formatés et des auditeurs associés devrait se faire au moyen d'une boucle parcourant le tableau des variations (Variation.ALL_VARIATIONS
) et pas au moyen d'un code quasi-identique répété six fois.
Notes
1 La méthode addPropertyChangeListener
permet d'observer n'importe quel attribut d'un objet qui respecte la norme JavaBeans. Cette norme spécifie un certain nombre de conditions qu'un objet doit satisfaire pour être considéré comme un composant réutilisable. Parmi ces conditions figure celle d'offrir des attributs (ou propriétés, properties) accessibles via des getter et setter respectant une convention de nommage spécifique. Ces attributs doivent de plus être observables au moyen de la méthode addPropertyChangeListener
. Les champs textuels de Swing respectent justement cette norme JavaBeans.