2015-12-17 1 views
1

Lors de la création d'une interface utilisateur graphique dans Swing, je suis toujours confronté à un problème de conception qui met fin au piratage. Je voudrais connaître la bonne pratique à ce sujet.OO Conception avec UndoManager et Listeners sur un composant JComponent

Prenons un exemple simple.

J'ai un composant JComponent sur lequel j'aimerais implémenter des actions annuler/rétablir, et quelques actions qui ajoutent/suppriment d'autres composants. Donc, je voudrais commencer à écrire:

public class MyComponent extends JComponent { 
    private UndoManager undo = new UndoManager(); 
    public void addComponent(JComponent comp) { 
     this.add(comp);//Add the component to the view 
     undo.addEdit(new ComponentAddedEdit(comp));//make this action undoable 
     fireComponentAdded(comp);//warn the listeners that the action occured 
    } 
} 

Puis commence le problème. Dans mon ComponentAddedEdit je pense à quelque chose comme:

public class ComponentAddedEdit extends AbstractUndoableEdit { 
    private final JComponent comp; 
    public ComponentAddedEdit(JComponent comp) {this.comp = comp;} 
    @Override 
    public void undo() throws CannotUndoException { 
     MyComponent.this.removeComponent(comp); 
    } 
    @Override 
    public void redo() throws CannotRedoException { 
     MyComponent.this.addComponent(comp); 
    } 
} 

Bien sûr, cela ne fonctionne pas parce que l'action redo va créer une nouvelle Edit à UndoManager. Je dois donc créer une nouvelle méthode comme ça:

public void addComponentNoUndo() { 
     this.add(comp);//Add the component to the view 
     fireComponentAdded(comp);//warn the listeners that the action occured 
} 

En fin de compte, juste pour l'action « ajouter », je me retrouve avec 3 méthodes avec des noms similaires: add, addComponent et addComponentNoUndo. Si j'ai plus d'actions, plus complexes, cela peut devenir très confus. Alors, comment ferais-tu ça?

+0

Avez-vous pensé à utiliser un modèle memento? –

+0

Je n'ai pas, mais maintenant que j'étudie cette option, je ne vois pas comment il pourrait résoudre le problème. Pourrais-tu me montrer comment tu écrirais le 'undo' avec un souvenir? IMO vous devez toujours être en mesure d'ajouter un composant sans déclencher une nouvelle modification, ce qui signifie que vous avez toujours besoin de la méthode 'addComponentNoUndo'. La seule différence est que cette méthode pourrait devenir privée. – Sharcoux

Répondre

0

Je ne suis pas vraiment dans le swing, donc je ne peux pas vous donner une réponse de mise en œuvre spécifique, mais voir ce tutorial on memento pattern.

Vous avez sûrement besoin de l'adapter à vos besoins, mais je pense que c'est la voie à suivre. Essayez d'écrire votre propre classe "state" plutôt que d'utiliser simplement une chaîne de caractères.

Je veux alors annuler quelque chose, charger l'ancien état. Si vous ne voulez pas que l'utilisateur puisse annuler quelque chose, ne chargez tout simplement pas l'état précédent, en disant à l'utilisateur que ce n'est pas possible. Pensez à ajouter un drapeau booléen "undoable" à votre classe "state".

EDIT

quelque chose comme

class state extends JComponent { 

    private boolean undoable; 
    private JComponent toSave; 

    public state (boolean undoable, JComponent toSave, ...) { 
     this.undoable = undoable; 
     this.toSave = toSave; 
     ... 
    } 
... 
} 
+0

Merci, mais le problème dans ce cas est que je devrais enregistrer l'état entier de mon objet à chaque fois, et le recréer complètement. Je préfère ne conserver que les modifications. Si je ne voulais pas recréer tout l'état, j'aurais besoin de méthodes très similaires à mon 'addComponentNoUndo'. Votre exemple de code n'est pas la partie que je n'ai pas pu comprendre. Ce qui me pose problème, c'est comment vous recréer l'état et avertir les auditeurs sans lancer un nouveau Edit. – Sharcoux

+0

Vous pouvez également enregistrer les modifications en tant que 'state'. 'redo' et' undo' iraient en avant ou en arrière dans votre histoire savedStates. quelque chose comme: 'annuler: nouvel état (true, this); this = getState (index -1) ' ' redo: this = getState (this.index +1) ' alors que vous n'enregistrez que les modifications dans votre classe d'état. (J'espère que vous comprenez ce que je veux dire) –

+0

Vous pouvez stocker les modifications comme 'HashMap ' où vous définissez les attributs modifiés de votre JComponent en tant que paires valeur-clé. Faire un 'getState' pourrait vous donner un' HashMap' que vous pouvez analyser pour les différences dans votre classe. –