IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Composants graphiques Android Discussion :

Faire un bouton "Undo"


Sujet :

Composants graphiques Android

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    78
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2011
    Messages : 78
    Points : 18
    Points
    18
    Par défaut Faire un bouton "Undo"
    Bonjour,

    Je suis débutant au niveau du développement androïde, je dois à présent effectuer un bouton "undo" sur mon application. Celle-ci permet d'effectuer des lignes, des ronds...
    Ce bouton me permettrait de revenir à l'action précédente. J'ai réussi à faire un bouton retour, qui me permet de retourner à l'activité précédent. J'aimerai avoir des conseils car je ne trouve pas grand chose la dessus et je ne vois pas trop comment faire ce bouton

    Merci

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    En général, pour réaliser une fonctionnalité d'UNDO, on procède en utilisant un journal, c'est à dire une liste d'actions : à chaque fois que l'utilisateur fait une action dans le programme, on l'enregistre dans le journal. On considère principalement 2 types d'actions : des actions réversibles et des actions non-réversibles. Les actions réversibles sont les actions telles qu'on peut faire ce qui correspond à l'inverse de ce que fait l'action : par exemple, une action qui dessine un cercle à pour action inverse l'action qui efface le cercle tout en laissant ce qu'il y avait avant de dessiner le cercle. Les actions non-réversibles sont les actions qui ne sont pas réversibles, de fait : par exemple, on peut considérer qu'une action qui sauvegarde dans un fichier est non réversible (il faudrait sauvegarder une copie du fichier écrasé pour qu'elle le soit).

    Ensuite, au niveau du fonctionnement, tant qu'on fait des actions réversibles, on les ajoute au journal : faire undo, c'est faire l'action inverse de la dernière action ajoutée au journal, et la supprimer du journal. Chaque fois qu'on fait une action non-réversible, on efface tout le journal : elle n'est pas réversible et rend toutes les actions précédentes non réversibles. On ne peut pas faire d'UNDO si le journal est vide, évidemment.

    Dans la pratique, réaliser une telle fonctionnalité peut être plus ou moins simple. Par exemple, dans une application de dessin vectoriel, où chaque action consiste ajouter des points, des segments, ou des polygones dans une liste, il est facile de faire la fonction réversible de l'ajout : il s'agit de supprimer tout simplement l'élément ajouté. Dans une application de dessin bitmap, c'est faussement simple : chaque fois qu'on dessine, on remplace la couleur de certains pixels par de nouvelles couleurs (on change leur couleur), donc on perd les anciennes couleurs. Et on peut en changer des milliers en une seule action (par exemple, l'action "effacer tout"). Une solution très simple serait de mémoriser l'image bitmap avant de faire l'action, ce qui permet de revenir en arrière (au dessin précédent), mais ça risque de devenir rapidement très gourmand en mémoire selon la taille de l'image. On peut définir une taille maximum de journal, au delà de laquelle on ne pourra plus faire d'undo, pour limiter la taille du journal en mémoire (par exemple, dire qu'on ne peut qu'annuler que les 20 dernières actions), ou encore ne mémoriser que les blocs de pixels remplacés, ce qui minimise la taille occupée par chaque action réversible dans le journal, ou adapter chaque action inverse à chaque action, pour optimiser (certaines mémoriseront une partie de l'image remplacée, d'autres feront autre chose).

    On peut également introduire la notion d'action neutre : elles ne sont pas réversibles (parce qu'on ne saurait pas programmer la fonction inverse), mais en fait ce n'est pas grave, parce qu'il n'y a pas besoin de les inverser pour réaliser un undo. Par exemple, une action d'impression : on ne peut évidemment pas faire que la feuille retourne dans l'imprimante et l'encre revienne dans les encriers, mais on s'en fout, faire un undo sur une impression, c'est juste supprimer l'action d'impression du journal. On pourrait même ne pas la mettre dans le journal, mais cela peut être troublant que certaines actions y soient et pas d'autres lorsque l'utilisateur fait plusieurs undos successifs. Mais, ça peut être aussi un choix. On peut inclure dans les actions neutres les actions qu'on ne veut pas rendre réversible : ouvrir un fichier dessin par exemple : on ne va pas faire une action qui ferme le dessin quand l'utilisateur fait UNDO (mais dans un autre contexte, cela pourrait avoir un sens).

    A noter, en plus, que si on mémorise les actions qu'on inverse à chaque undo, on peut faire très facilement la fonction redo : chaque fois qu'on fait undo, on ajoute l'action annulée dans une liste (un journal d'action pour le redo), et faire redo, c'est faire la dernière action ajoutée dans cette liste, la remettre dans le journal d'action du undo, la supprimer du journal d'action du redo. A chaque fois qu'on fait une action normale, la mettre dans le journal du undo (ou vider le journal si l'action est non réversible) et vider le journal de redo qui devient caduque du fait qu'on fait une nouvelle action.

    Pour l'application propre à Android, je laisse éventuellement les spécialistes du domaine intervenir plus spécifiquement.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    78
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2011
    Messages : 78
    Points : 18
    Points
    18
    Par défaut
    Pour l'instant j'ai declarer mon bouton undo:
    Button btnUndo;
    j'ai déclarer ensuite deux
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     ArrayList<Path> path1 = new ArrayList<Path>();
    ArrayList<Path> path2 = new ArrayList<Path>();
     
    btnUndo = (Button) findViewById(R.id.btnUndo);
    		btnUndo.setOnClickListener(this);
    ensuite ma fonction Undo
    // Fonction "Undo"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    	public void undo() {
    		if (path1.size() > 0) {
    			Paths2.add(path1.remove(path1.size() - 1));
    			p.invalidate();
    		}
    	}
    jusque là je pense que c'est bon.

    ensuite je pense qu'il faut enregistrer mes actions dans la ArrayList mais je ne vois pas comment faire je trace un cercle j'aimerai enregistrer cet action dan larraylist pour pouvoir la memoriser, je pense que c'est ici que je dois ajouter a mon arraylist mais comment ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    private void onTouchUp(MotionEvent event) {
    		switch (choisir) {
                      case SELECT_cercle:
    			p.add(new CERCLE("Cercle", (int) event.getX(), (int) event
    					.getY(), 2));
    			p.invalidate();
    			break;
    }
    merci de votre aide

  4. #4
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Conseil...

    Pour avoir effectué ce genre de truc un nombre incalculable de fois....

    Utilise des interfaces pour les actions:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    interface Action
    {
          public void redo();
    }
     
    interface UndoableAction extends Action
    {
          public void undo();
    }

    Ensuite... un simple manager (singleton).
    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
     
    class ActionManager
    {
              public static ActionManager  getInstance()
              {
                   if (_instance == null) _instance =new ActionManager();
                   return _instance;
              }
     
              public static void execute(Action action)
              { getInstance().performAction(action); }
     
              public static void undo()
              { getInstance().performUndo(); }
     
              public static void redo()
              { getInstance().performRedo(); }
     
             private ArrayList<UndoableAction>   redoList = new ArrayList<UndoableAction>();
             private ArrayList<UndoableAction>  undoList = new ArrayList<UndoableAction>();
             private boolean reallyDirty = false;
     
             public boolean  isDirty()
             {
                  return this.reallyDirty || !hasUndo();
             }
     
             public boolean hasUndo()
             {
                  return !this.undoList.isEmpty();
             }
     
             public boolean hasRedo()
             {
                  return !this.redoList.isEmpty();
             }
     
     
             public void performAction(Action action)
             {
                  action.redo();
                  this.redoList.clear();
                  if (action instanceof UndoableAction) {
                       this.undoList.add((UndoableAction)action);
                  } else {
                       this.undoList.clear();
                       this.reallyDirty = true;
                 }
             }
     
             public void performRedo()
             {
                  if (! this.redoList.isEmpty()) {
                      UndoableAction action = this.redoList.get(this.redoList.size()-1);
                      this.redoList.remove(this.redoList.size()-1);
                      action.redo();
                      this.undoList.add(action);
                 }
             }
     
             public void performUndo()
             {
                  if (! this.undoList.isEmpty()) {
                      UndoableAction action = this.undoList.get(this.undoList.size()-1);
                      this.undoList.remove(this.undoList.size()-1);
                      action.undo();
                      this.redoList.add(action);
                 }
             }
     
             public void reset()
             {
                 this.undoList.clear();
                 this.redoList.clear();
                 this.reallyDirty = false;
             }
     
     
             private ActionManager() { /* make the class not instanciable outside of itself */ }
     
     
    }
    Et ensuite... tu ne passes plus que par "l'ActionManager"....
    A noter qu'on peut aussi implémenter ce manager par "document" si l'application autorise plusieurs documents ouverts en parallèle.

    Exemple d'utilisation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ActionManager.execute(new InsertTextAction(xxxxxxxx));   // InsertTextAction implémente "Action", et "UndoableAction" si un "undo" est possible.

    Exemple d'action:
    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
     
    class AddCircleAction implements UndoableAction
    {
           public AddCircleAction(... paramètres pour ajout d'un cercle ...)
           { ... stockage des paramètres dans l'action ... }
     
           public void redo()
           {
              ... on ajoute le cercle... (on stocke eventuellement une référence vers ce cercle dans l'action)
           }
     
           public void undo()
           {
               ... on enleve le cercle ajouté (et on supprime la référence).
           }
    }
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  5. #5
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Je rappelle que la "charte" est de ne *pas* utiliser les messages privés (sauf pour contacter directement quelqu'un sur un aspect précis n'ayant aucun rapport avec la discussion ici).

    Bonjour,

    Je ne sais pas si vous avez reçu mon message, j'ai donc mis comme vous me l'avez conseillé deux interfaces et une classe ActionManager. Ensuite ma classe Source c'est la ou je fais mon cercle j'ai mis implements UndoableAction et du coup j'ai implementer mes fonctions undo et redo. j'ai ensuite mis que lorsque je cliquer sur le bouton undo alors ActionManager.undo() mais ca ne marche pas je suis un peu perdu


    On peut voir le code d'ajout de cercle ?
    La classe "AddCircleAction" ?
    Et la classe qui appelle le "Undo" ?

    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  6. #6
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    78
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2011
    Messages : 78
    Points : 18
    Points
    18
    Par défaut
    Voici la classe qui me permet de dessiner mes cercles, je n'ai pas implémenter mes méthodes undo et redo car elle ne marcher pas, est ce à cet endroit qu'il faut les mettre ?

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
     
    public class Cercle implements UndoableAction {
     
    private Bitmap bitmap = null;
    	private Canvas canvas = null;
    	private Point center = null;
    	private Paint paint = null;
    	private double x = 10, y = 20;
    	private static final int rayon = 4;
     
     
    	String name;
     
    	public Cercle() {
    		center = new Point();
     
    	}
     
     
     
            public Cercle(String name, int x, int y) {
    		this();
    		setName(name);
    		setPosition(x, y);
    	}
     
                public void doBitmap(int width, int height) {
     
    			bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
    			canvas = new Canvas(bitmap);
    			paint = new Paint();
    			paint.setColor(Color.BLACK);
     
    			canvas.drawCircle(center.x, center.y, rayon, paint);
    		}
    	}
     
            public void setPosition(int x, int y) {
    		center.x = x;
    		center.y = y;
    	}
     
    	@Override
    	public void redo() {
    		// TODO Auto-generated method stub
     
    	}
     
    	@Override
    	public void undo() {
    		// TODO Auto-generated method stub
     
    	}
    }
    Sinon j'ai effectuer les deux interfaces comme vous Action et UndoableAction ainsi que la classe ActionManager ensuite j'ai fait le lien avec mon bouton undo créer dans mon fichier xml ou j'indique qu'il faut faire la fonction undo lorsque le bouton est cliqué

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public void onClick(View v) {
       if (v == btnUndo) {
          ActionManager.undo();
       }
    }
    et une classe :
    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
     
    public class InsertionCercleListener implements OnTouchListener {
     
    Cercle c;
    private int select;
    private Plan p;
    public static final int SELECT_CERCLE = 1;
     
    private void onTouchUp(MotionEvent event) {
    		switch (select) {
    			case SELECT_CERCLE:
    			p.add(new Cercle("cercle1", (int) event.getX(), (int) event
    					//.getY()));
    			p.invalidate();
    			break;
    		}
    }

  7. #7
    Modérateur
    Avatar de kolodz
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2008
    Messages
    2 211
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 211
    Points : 8 316
    Points
    8 316
    Billets dans le blog
    52
    Par défaut
    Le principe du processeur de commande est de tout faire passer par lui.
    C'est le seul à faire faire quelque chose au niveau de ton interface.
    Soit tu lui demande de réaliser une commande :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ActionManager.excute(new Cercle("cercle1", (int) event.getX(), (int) event.getY()));
    Soit tu lui demande d'annuler ce que tu viens de faire :
    Soit tu lui demande de refaire ce que tu viens de faire :
    L'action manager gardera un trace de toutes les commandes réalisées. il faut bien imaginer que c'est lui le boss ! Si c'est pas passé par son bureau, ça n'existe pas !

    Cordialement,
    Patrick Kolodziejczyk.

    Note :
    Sachant que certains réalises des commandes de type non historisé. Celle-ci sont exécuté par le processeur, mais n’affecte pas l'historique.
    Si une réponse vous a été utile pensez à
    Si vous avez eu la réponse à votre question, marquez votre discussion
    Pensez aux FAQs et aux tutoriels et cours.

  8. #8
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    78
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2011
    Messages : 78
    Points : 18
    Points
    18
    Par défaut
    Merci pour vos conseils, j'ai bien compris le principe et vos différents exemples seulement dans mon cas je ne pense pas avoir besoin d'utiliser tout çà, j'ai une méthode doBitmap qui gère pour tout mes ajouts sur mon plan donc je pense quel peut correspondre à la fonction redo, il me reste maintenant a savoir supprimer un élément bitmap graphiquement. J'ai réussi a faire après sélection de l'élément la suppression de celui-ci donc je pense que je pourrais peu être l’utiliser pour supprimer cet élément il faut que je trouve comment le supprimer sans le sélectionner.

+ Répondre à la discussion
Cette discussion est résolue.

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo