OVH Cloud OVH Cloud

Annuler et Refaire plusieurs fois...

17 réponses
Avatar
Armando R.
Bonjour,
Dans mon application, j'utilise la commande CLS pour effacer la dernière
opération effectuée sur un PictureBox.
je voudrais pouvoir annuler plusieurs opérations l'une après l'autre et
aussi revenir en arrière. quelqu'un aurait il un petit exemple que je puisse
adapter à mon application ?
merci d'avance...

7 réponses

1 2
Avatar
Patrice Henrio
Cette conversation répond justement à une question que j'allais poser. La
réponse de ng me convient parfaitement car je travaille déjà en vectoriel,
plus exactement en tableau de points définissant des polygones.
Le fond du problème reste le juste équilibre entre le temps de calcul et
l'espace mémoire.
En effet, ma table vectorielle est calculée et décrit environ un millier de
points de type PointApi pour utiliser les API graphiques. Les stocker prend
de l'espace mémoire, les calculer du temps processeur. Pour l'instant sur un
proc 1,2 GHz, on ne voit pratiquement pas de pause dans l'affichage.
Mais je vais quand même creuser l'idée du stockage. L'idée de créer une
classe me tente bien aussi, l'une des variables pouvant être l'état
précédent (à priori je n'ai besoin au plus que d'un retour en arrière : fond
de carte et dessin sur la carte).
Serait-il possible aussi de considérer le fond de carte comme le fond du
pictureBox et le dessin se ferait directement dessus. Le fond ne changeant
que selon certains évènements seulement ?

"ng" a écrit dans le message de news:

Salut,

Pour ce qui est du calcul de la modification entre 2 actions (ce que tu
appelles delta), cela me parait être une très bonne solution bien qu'assez
groumande en CPU en VB je pense.
Et le stockage ne serait pas si évident, il faudrait détecter toutes les
regions modifiées et les mettre dans un tableau de structures définie
comme suit (enfin c'est ce que je ferai, il y a peut être une meilleure
approche) :

Public Type Region
tCoord As Point 'structure contenant X, Y, la position del a région
tRegion As Region 'qui pourrait être un StdPicture ou tt autre objet
pour stocker une image
End Type

Il suffirait ensuite de recoller les morceau sur l'image pour revenir en
arrière.

--
Nicolas G.
FAQ VB : http://faq.vb.free.fr
API Guide : http://www.allapi.net
Google Groups : http://groups.google.fr/
MZ-Tools : http://www.mztools.com/

Patrick Philippot wrote:
Armando R. wrote:
je voudrais pouvoir annuler plusieurs opérations l'une après l'autre



Bonjour,

La mise en place d'un mécanisme d'undo/redo nécessite de répondre à 2
questions: comment et quoi?

Comment?
-------------

En général, un tel mécanisme va être mis en oeuvre par le biais d'une
double pile. Au fur et à mesure de leur exécution, les actions de
l'utilisateur sont empilées sur la pile Undo. Si une commande Undo est
déclenchée, la dernière action exécutée est dépilée, son effet est
annulé (voir plus bas) et l'action est réempilée sur la pile Redo afin
de satisfaire une éventuelle commande Redo.

Les piles en questions peuvent être soit limitées en taille (nombre
limité de undo/redo), soit être ajustées dynamiquement. En VB, il me
paraît assez simple d'implémenter une classe Pile à partir d'un objet
Collection.

Une alternative à la méthode des piles est la méthode de la sauvegarde
incrémentale utilisée par exemple par Word en connexion avec les
storages (voir interface COM IStorage pour les explication sur les
storages - fichiers composites ou compound documents). Tous les
documents Office sont en fait des storages (système de fichier à
l'intérieur d'un fichier). Word utilise pour son système d'Undo/Redo
la possibilité que donne le storage de travailler en mode incrémental
(on ne stocke que ce qui change dans des répertoires séparés)
associée à la capacité des storages de travailler en mode
transactionnel (commit / rollback). Cette approche est très
intéressante mais beaucoup plus complexe et nécessite une bonne
connaissance du COM et de la manipulation des storages.

Quoi?
-------

La question qui vient immédiatement derrière est "que va-t-on mettre
sur ces piles?". Il est évident que stocker l'état complet du
document pour chaque action, surtout dans le cas des images, amène
rapidement soit à une saturation de la mémoire, soit à une forte
limitation du nombre d'actions undo autorisées. Cela peut cependant
faire l'affaire dans certains cas.

L'approche la plus efficace est cependant de stocker un ensemble de
données décrivant la commande qui vient d'être réalisée. A chaque
commande mise à la disposition de l'utilisateur doit correspondre un
objet "commande inverse" qui décrit l'action à entreprendre pour
annuler éventuellement l'effet de la commande qui va être exécutée.
C'est cette description que l'on stocke sur la pile Undo. A
contrario, on stockera sur la pile Redo l'inverse de la "commande
inverse" que l'on vient de dépiler de la pile Undo.

Il est clair que la mise en oeuvre de cette approche nécessite une
réflexion préalable sur la manière dont les commandes utilisateurs
sont traitées et décrites dans le programme. Ce qui veut dire que
chaque commande (et commande inverse) doit être décrite par un objet
qui contient toutes les informations nécessaires à l'exécution de
l'action ou à la création d'une commande inverse annulant l'effet de
cette action. Ce n'est pas un travail très simple en VB dont les
capacités objet sont très limitées.

Pour les images, une autre approche consisterait à ne stocker que le
"delta" entre les images (avant et après l'action utilisateur). ce
delta peut se calculer en comparant les 2 images par quelques
opérations binaires simples. L'inconvénient, c'est que le résultat
peut être de taille très petite ou de la même taille que l'image
complète selon l'action qui aura été exécutée. en cela, cette
approche est intermédiaire entre la méthode décrite ci-dessus
(commandes inverses) et l'approche "stockage de chaque version du
document".






Avatar
Patrick Philippot
Armando R. wrote:
bon... je crois que c'est pas gagné pour moi !... :((



Courage, courage. C'est comme cela que l'on apprend :-) .

Écrire un mécanisme d'undo/redo fait partie des tâches relativement
complexes à écrire et assez difficilement généralisable. C'est pour cela
qu'il est difficile de trouver du code tout fait qui s'appliquerait en
toutes circonstances, quoiqu'il existe des design patterns sur ce sujet
(avec des implémentations pour MFC, .Net,... mais rarement pour VB).
Faire une recherche sur le pattern "Memento", par exemple. Mais même un
algorithme bien construit dans un design pattern ne peut pas deviner
comment définir les actions elles-mêmes. Cela est spécifique à chaque
programme. Il peut néanmoins fournir la structure de gestion des piles
et des objets "commandes".

En outre, les design patterns undo/redo s'appuient souvent sur un autre
design pattern de gestion structurée des commandes utilisateur comme MVC
(Model-View-Controller). L'un va rarement sans l'autre. Et MVC en VB6,
je ne vois pas.

Maintenant, la solution de repli, c'est de remplacer votre PictureBox
par un contrôle image plus élaboré autorisant l'édition et l'undo/redo.
Mais ce n'est pas gratuit. Voir www.componentsource.com , section
Imaging.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
dark poulpo
exact,

dou le add_push(byref quoi as variant)

et comme jai dit, il contourne le principe de lheritage en collant
directement les classe "herité" qui ne sont plus "herité"

--
-----
http://dark.freezee.org/
- Dark Update v1.0
- Dark Emule v0.44b r4
- Dark 3D-X (le desktop 3d pour windows) (----------> v0.7 beta dispo)
Avatar
Patrick Philippot
Patrick Philippot wrote:
Quoi?



Concernant la question du stockage dans un programme graphique, je
rappelle l'existence des fichiers mappés en mémoire (MMF - memory mapped
file). Ce mécanisme permet de voir "comme si elles étaient stockées en
mémoire" des quantités importantes de données. En fait, les MMF ne sont
pas gérés différemment de la mémoire virtuelle à ceci près que le
système effectue la pagination dans un fichier désigné par l'utilisateur
au lieu d'utiliser le fichier de pagination système (il suffit
d'ailleurs d'utiliser le handle 0xFFFFFFFF pour passer d'un fichier
custom au fichier de pagination système).

L'avantage de cette approche est de pouvoir travailler comme si on
stockait les images dans un énorme buffer mémoire alors qu'en fait, le
système gère automatiquement les allers-retours entre mémoire physique
et disque au fur et à mesure des besoins. Dans le cas d'un undo/redo, la
pagination se passerait sûrement très bien puisqu'il n'y aurait pas
accès aléatoire mais accès en séquence dans le buffer au fur et à mesure
des empilements / dépilements. Les pages (images) dont on a besoin
auraient donc de très fortes chances de se trouver en mémoire physique
au moment où on voudrait les exploiter et l'impact sur les performances
serait minimum. Je rappelle que les performances des MMFs sont
exactement les mêmes que celles du gestionnaire de mémoire virtuelle de
Windows: c'est le même mécanisme qui les gère.

La seule contrainte concernant l'utilisation des MMF, c'est qu'il faut
connaître à l'avance la taille maximale du MMF au moment de sa création.
Dans notre cas, cela voudrait dire qu'il faudrait fixer un nombre
maximum d'undo/redo et calculer la taille du MMF au moment de sa
création en multipliant ce nombre par la taille maximum d'une image en
mémoire.

Cette approche permettrait de ne pas se compliquer trop la vie en termes
de stockage : on stockerait la totalité de l'image.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Patrick Philippot
Il y a un exemple d'interfaçage avec l'API des MMF en VB sur cette page:

http://vb.mvps.org/samples/project.asp?id=mapfile

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Patrick Philippot
Patrick Philippot wrote:
Maintenant, la solution de repli, c'est de remplacer votre PictureBox
par un contrôle image plus élaboré autorisant l'édition et
l'undo/redo. Mais ce n'est pas gratuit. Voir www.componentsource.com
, section Imaging.



Voir par exemple Metadraw:

http://www.bennet-tec.com/btproducts/MetaDraw/MetaDraw.htm

Mais franchement, ce n'est pas donné.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Patrice Henrio
Merci je vais creuser cette piste.
"Patrick Philippot" a écrit dans le
message de news:
Il y a un exemple d'interfaçage avec l'API des MMF en VB sur cette page:

http://vb.mvps.org/samples/project.asp?id=mapfile

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr



1 2