Annulation NSBEzierPath
Radada
Membre
Salut
comme dis sur un précédent post, je suis en train de réaliser un exercice du bouquin de Aaron Hilleglass. Il faut faire une toute petite appli qui permet de dessiner des ovales (avec une NSBezierPath).
Pour les courageux (moi donc ^^), il faut ajouter la sauvegarde et l'annulation.
Pour la sauvegarde, j'ai à peu près réussi à m'en sortir.
Par contre c'est une autre paire de manche pour l'annulation. J'ai décidé (peut être à tort) d'utiliser un seul objet NSBezierPath et de faire des appendBezierPathWithOvalInRect et de faire ré-afficher le path quand besoin.
Du coup, je n'arrive pas à voir comment implémenter l'annulation. Il n'y a pas de conception KVC, donc pas possible de réailser un addObserver (enfin, je pense) et comme il n'y a pas de moyen d'enlever (enfin, à ma connaissance) un seul des ovales, je ne peux pas utiliser le NSUndoManager prepareInvocationTarget.
D'où ma question : peut-on réaliser un mécanisme d'annulation avec de type d'objet et comment?
Sinon, j'avais pensé à une autre solution : plutôt qu'utiliser un appendBezierPathWithOvalInRect, je pourrais gérer un NSMutableArray de path et gérer un NSBezierPath par ovale dessiné. Du coup, je devrais pouvoir gérer l'ajout de NSBezierPath dans le vecteur et l'annulation se ferait par suppression du(des) dernier(s) path dans le NSMutableArray. Lors de l'affichage, il me suffirait de boucler sur les objets du NSMutableArray et de les afficher tour à tour. Mais cette méthode, si elle me semble correcte pour l'annulation, ne me parait pas terrible tant en conception qu'en perf non?
Pour voir le code --> voir la PJ. Ou sinon, voici la gestion des NZBezierPath dans mon NSView :
Merci
comme dis sur un précédent post, je suis en train de réaliser un exercice du bouquin de Aaron Hilleglass. Il faut faire une toute petite appli qui permet de dessiner des ovales (avec une NSBezierPath).
Pour les courageux (moi donc ^^), il faut ajouter la sauvegarde et l'annulation.
Pour la sauvegarde, j'ai à peu près réussi à m'en sortir.
Par contre c'est une autre paire de manche pour l'annulation. J'ai décidé (peut être à tort) d'utiliser un seul objet NSBezierPath et de faire des appendBezierPathWithOvalInRect et de faire ré-afficher le path quand besoin.
Du coup, je n'arrive pas à voir comment implémenter l'annulation. Il n'y a pas de conception KVC, donc pas possible de réailser un addObserver (enfin, je pense) et comme il n'y a pas de moyen d'enlever (enfin, à ma connaissance) un seul des ovales, je ne peux pas utiliser le NSUndoManager prepareInvocationTarget.
D'où ma question : peut-on réaliser un mécanisme d'annulation avec de type d'objet et comment?
Sinon, j'avais pensé à une autre solution : plutôt qu'utiliser un appendBezierPathWithOvalInRect, je pourrais gérer un NSMutableArray de path et gérer un NSBezierPath par ovale dessiné. Du coup, je devrais pouvoir gérer l'ajout de NSBezierPath dans le vecteur et l'annulation se ferait par suppression du(des) dernier(s) path dans le NSMutableArray. Lors de l'affichage, il me suffirait de boucler sur les objets du NSMutableArray et de les afficher tour à tour. Mais cette méthode, si elle me semble correcte pour l'annulation, ne me parait pas terrible tant en conception qu'en perf non?
Pour voir le code --> voir la PJ. Ou sinon, voici la gestion des NZBezierPath dans mon NSView :
<br />#pragma mark INITIALISATIONS<br />- (id)initWithFrame:(NSRect)frame {<br /> self = [super initWithFrame:frame];<br /> if (self) {<br /> // Initialization code here.<br /> path = [[NSBezierPath alloc]init]; <br /> color = [NSColor blackColor];<br /> currentPoint = NSZeroPoint;<br /> }<br /> return self;<br />}<br /><br />#pragma mark DESSINS<br />- (void)drawRect:(NSRect)rect {<br /> // Drawing code here.<br /> <br /> NSRect bounds = [self bounds];<br /> [[NSColor whiteColor] set];<br /> [NSBezierPath fillRect:bounds];<br /> <br /> //[self addObserver:path forKeyPath:@"path" options:NSKeyValueObservingOptionOld context:nil];<br /> if (currentPoint.x > 0 && currentPoint.y > 0)<br /> {<br /> [path appendBezierPathWithOvalInRect:[self currentRect]];<br /> [color set];<br /> [path fill];<br /> }<br />}<br /><br />-(NSRect)currentRect<br />{<br /> float minX = MIN(originPoint.x, currentPoint.x);<br /> float maxX = MAX(originPoint.x, currentPoint.x);<br /> float minY = MIN(originPoint.y, currentPoint.y);<br /> float maxY = MAX(originPoint.y, currentPoint.y);<br /> return NSMakeRect(minX, minY, maxX-minX, maxY-minY);<br />}<br /><br />
Merci
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
C'est en effet une première idée. Que faire d'autre ? Faire une NSView par ovale et faire des addSubview, c'est nettement moins économique !
Oki doki, merci. Donc selon toi, il n'y a pas d'autre solution plus économique?
Merci Philippe
Pour enregistrer un état auprès de l'undo manager, tu utilises typiquement sa méthode -registerUndoWithTarget:selector:object:.
Cette méthode va envoyer un [retain] à object.
Tes deux méthodes sont possibles (un seul, ou un tableau de Bezier paths), mais selon le cas, object sera une référence sur le NSBezierPath ajouté, ou sur une copie (parce que si tu n'as qu'un seul NSBezierPath, ajouter un oval modifie le bezier path, mais pas la référence).
Relis le chapitre du livre sur l'Undo, c'est la meilleure explication qu'il m'ait été donné de lire. Il faut juste comprendre que chaque méthode de modification, doit avoir une méthode d'annulation totalement réciproque pour que l'annulation et le rétablissement fonctionnent tous les deux.
Bon, je sais pas si je suis très clair.
Salut Ceroce et merci de ta réponse.
Justement mon problème était que je ne voyais pas comment faire une méthode réciproque de l'ajout, d'où l'idée du NSMutableArray. Je ne trouvais pas ça très propre (en tout cas en comparaison de ce que j'ai l'habitude de faire en c++), mais ça me rassure de savoir que c'est la bonne méthode. Je vais m'y mettre cet AM
Merci à tous en tout cas...
Mais ça a aussi l'avantage comme le note Céroce de rendre tes ovales individuels : modifier leur ordre de dessin (premier-plan/arrière-plan), modifier leur couleur de remplissage ou de trait (car si tu dessines tout en tant qu'un seul BezierPath, tu ne peux pas mettre des couleurs différentes puisque c'est un BezierPath unique), ...