Salut,
Déjà confronté plusieurs fois à ce problème, je cherche un pattern qui puisse résoudre mon problème.
J'ai un modèle et une vue, chacun possédant des composants écoutables (par des listeners).
Le modèle peut être modifié par la vue (par exemple, lors de la modification d'un textfield, un champ String est affecté sur le modèle), mais la vue peut aussi être modifiée par le modèle (si le champ String est affecté par autre chose, une autre vue par exemple, la vue doit se mettre à jour).
Le problème est que si on code bêtement les listeners, avec le modèle qui écoute la vue et la vue qui écoute le modèle, dès qu'il y a une modification, on tourne en boucle :
- le textfield est modifié
- donc la String dans le modèle est modifiée
- donc le textfield est modifié
- donc la String dans le modèle est modifiée
- donc le textfield est modifié
- ...
- merde on tourne en rond merde on tourne en rond merde on tourne en rond...
Pour éviter ce cycle, j'avais pensé à ce pattern :
Le problème, c'est qu'une modification sur la vue peut modifier le modèle, qui lui même pourra modifier AUTRE CHOSE sur la vue.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 public class JFrame { //par exemple private final Controller CONTROLLER = new Controller(); public JFrame() { //... unComposantDeLaVue.addActionListener(CONTROLLER); monComposantDeModele.addModeleListener(CONTROLLER); } private class Controller implements ActionListener, ModeleListener { private boolean modelAction; private boolean viewAction; @Override public void actionPerformed(ActionEvent e) { if(!modelAction) { viewAction = true; //modification du modèle viewAction = false; } } @Override public void modeleChanged() { if(!viewAction) { modelAction = true; //modification de la vue modelAction = false; } } } }
Par exemple, si j'ai 2 JSpinner, représentant les valeurs A et B.
Si je modifie graphiquement A, ça appelle une fonction sur le modèle, qui change évidemment A mais qui fait un calcul sur B. La modification de A ne doit pas se répercuter sur la vue (car c'est la source de l'action), mais par contre la modification de B doit être signalée à la vue...
Connaissez-vous un joli pattern qui règle ce problème?
Car là à part faire un booléen par composant graphique, qui serait associé à l'évènement correspondant sur le modèle, je ne vois pas...
Une idée?
EDIT: je crois que j'ai trouvé une solution (je testerai demain).
En gros, lorsque le modèle est modifié, on regarde si ça n'est pas le composant graphique susceptible de l'avoir modifié qui est source de l'évènement.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 public class JFrame { //par exemple private final Controller CONTROLLER = new Controller(); public JFrame() { //... unComposantDeLaVue.addActionListener(CONTROLLER); monComposantDeModele.addModeleListener(CONTROLLER); } private class Controller implements ActionListener, ModeleListener { private boolean modelAction; private Object viewActionSource; @Override public void actionPerformed(ActionEvent e) { if(!modelAction) { viewActionSource = e.getSource(); //modification du modèle viewActionSource = null; } } @Override public void modeleChanged() { if(viewActionSource != composantAssocié) { modelAction = true; //modification de la vue modelAction = false; } } } }
Partager