Drag objet par objet

CeetixCeetix Membre
02:28 modifié dans API AppKit #1
Bonsoir !
Voilà , j'ai un soucis de réflexion.

J'ai dessiner 3 rectangles dans un NSView. Ils sont tous les 2 reliés à  un point d'encrage dans ma vue avec une droite.
Je peux dragger mes rectangle tous ensemble et quand je lâche ma souris, ils rejoignent le point d'encrage. Le truc c'est que j'aimerai pouvoir dragger les rectangle un par un ... Je vois pas trop comment m'y prendre.
Voici mon code et je vous mets mon projet si vous voulez voir.

.h

<br />#import &lt;Cocoa/Cocoa.h&gt;<br /><br />@interface Ball : NSView {<br />	Ball *maBalle;<br />	CGFloat x;<br />	CGFloat y;<br />	NSPoint posSouris;<br />	NSTimer *timer;<br />	BOOL etat;<br />	<br />	NSRect tableauDeDepart;<br />	NSRect tableauDeRect[3];<br />	NSColor *couleur[3];<br />	NSRect rectangle;<br /><br />}<br /><br />@end<br /><br />


.m

#import &quot;Ball.h&quot;<br /><br />@implementation Ball<br /><br />- (id)initWithFrame:(NSRect)frame {<br />&nbsp; &nbsp; self = [super initWithFrame:frame];<br />&nbsp; &nbsp; if (self) {<br />		/* Coordonnée du premier rectangle au lancement de l&#39;app */<br />		x = 10;<br />		y = 100;<br />	}<br />&nbsp; &nbsp; return self;<br />}<br /><br />- (void)drawRect:(NSRect)rect {<br />	<br />	/* Je colore ma vue */<br />	[[NSColor grayColor] set];<br />	NSRectFill ( [self bounds] );<br />	<br />	/* compteur */<br />	int i;<br />	<br />	/* Je dessine mon rectangle témoin et le met dans ma premiere case de tableau */<br />	tableauDeDepart = NSMakeRect(x, y, 30, 30);<br />	tableauDeRect[0] = tableauDeDepart;<br />	<br />	/* définition d&#39;une couleur */<br />	couleur[0] = [NSColor redColor];<br />	<br />	/* le rectangle que je vais imprimer recoit le rectangle de la 1ere case du tableauRect */<br />	rectangle = tableauDeRect[0];<br />	<br />	for( i = 0; i&lt;3 ; i ++)<br />	{<br />	<br />		tableauDeRect[i] = rectangle;<br />		couleur[i] = [NSColor redColor];<br />		<br />		/* Initialisation des deux points de ma droite */<br />		NSPoint p1 = NSMakePoint(rectangle.origin.x, rectangle.origin.y);<br />		NSPoint p2 = NSMakePoint(200, 300);<br />		<br />		/* Je commence à  tracer ma droite */<br />		NSBezierPath *tracer = [NSBezierPath bezierPath];<br />		[tracer moveToPoint:p1];<br />		[tracer lineToPoint:p2];<br />		<br />		/* Ma droite sera bleue */<br />		[[NSColor blueColor] set];<br />		[tracer stroke];<br />		<br />		/* Je décale mon prochain rectangle de +40px sur x */<br />		rectangle.origin.x +=40;		<br />	}<br />	<br />	/* Je rempli mes rectangles */<br />	NSRectFillListWithColors ( tableauDeRect, couleur, 3);<br />}<br /><br />-(void)mouseDown:(NSEvent *)theEvent {<br />	<br />	/* J&#39;arrête le timer qui appelle elast() */<br />	[timer fire];<br />	<br />	/* Par sécurité une variable qui permet de savoir si je dois rentrer dans if de elast() */<br />	etat = YES;	<br />	<br />}<br /><br />- (void)mouseDragged:(NSEvent *)theEvent {<br />	<br />	/* Position de souris */<br />	posSouris = [theEvent locationInWindow];<br />	<br />	/* mes coordonnées de rectangle deviennent les coordonnées de ma souris */ <br />	x = posSouris.x;<br />	y = posSouris.y;<br />	<br />	/* Je redessine */<br />	[self setNeedsDisplay:YES];<br />}<br /><br />- (void)mouseUp:(NSEvent *)theEvent {<br />	/* Mon etat devient NO pour que je puisse entrer dans le if de elast()*/<br />	etat = NO;<br />	<br />	/* Appel à  la fonction elast() */<br />	[self elast];	<br />}<br /><br />-(void)elast<br />{<br />	if(etat == NO)<br />	{<br />		<br />		/* En fonction de la position du rectangle je le replace à  mon point d&#39;encrage de ligne */<br />		<br />		if(x &lt;= 200 &amp;&amp; y &lt;= 300)<br />		{<br />			x = x + fabs(((200 - x)/100));<br />			y = y + fabs(((300 - y)/50));<br />		}<br />		<br />		if(x &gt;= 200 &amp;&amp; y &lt;= 300)<br />		{<br />			x = x - fabs(((200 - x)/100));<br />			y = y + fabs(((300 - y)/50));<br />		}<br />		<br />		if(x &lt;= 200 &amp;&amp; y &gt;= 300)<br />		{<br />			x = x + fabs(((200 - x)/100));<br />			y = y - fabs(((300 - y)/50));<br />		}<br />		<br />		if(x &gt;= 200 &amp;&amp; y &gt;= 300)<br />		{<br />			x = x - fabs(((200 - x)/100));<br />			y = y - fabs(((300 - y)/50));<br />		}<br />		<br />		/* Je redessine */<br />		[self setNeedsDisplay:YES];<br />		<br />		/* On actualise elast() toutes le 1ms pour avoir cet effet d&#39;animation */<br />		timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(elast) userInfo:nil repeats:NO];	<br />	}<br />}<br /><br />@end<br />




J'ai essayé de tout bien commenter  8--)
«1345678

Réponses

  • schlumschlum Membre
    02:28 modifié #2
    Pourquoi écrire 23 lignes :
    if(x &lt;= 200 &amp;&amp; y &lt;= 300)<br />{<br />	x = x + fabs(((200 - x)/100));<br />	y = y + fabs(((300 - y)/50));<br />}<br /><br />if(x &gt;= 200 &amp;&amp; y &lt;= 300)<br />{<br />	x = x - fabs(((200 - x)/100));<br />	y = y + fabs(((300 - y)/50));<br />}<br /><br />if(x &lt;= 200 &amp;&amp; y &gt;= 300)<br />{<br />	x = x + fabs(((200 - x)/100));<br />	y = y - fabs(((300 - y)/50));<br />}<br /><br />if(x &gt;= 200 &amp;&amp; y &gt;= 300)<br />{<br />	x = x - fabs(((200 - x)/100));<br />	y = y - fabs(((300 - y)/50));<br />}
    


    Au lieu de 8 ?
    if(x&lt;=200)<br />	x += fabs(((200-x)/100));<br />if(x&gt;=200)<br />	x -= fabs(((200-x)/100));<br />if(y&lt;=300)<br />	y += fabs(((300-y)/50));<br />if(y&gt;=300)<br />	y -= fabs(((300-y)/50));
    


    Puis il me paraà®t bizarre ce code... pourquoi <=200 au lieu de <=0 ??
  • CeetixCeetix Membre
    02:28 modifié #3
    Lol eu oui en effet.
    Pour 200 c'est juste que dans mon exemple mon point d'encrage de droite est en (200,300) .
  • AliGatorAliGator Membre, Modérateur
    02:28 modifié #4
    dans 1237001166:

    Pourquoi écrire 23 lignes :
    [...]
    Au lieu de 8 ?
    Et pourquoi en écrire 8 au lieu de 2 ?
    Déjà  attention schlum, tes conditions ne sont pas exclusives... dans le cas où x est précisément égal à  200, tu vas passer dans les 2 premières conditions au lieu d'une seule.
    Mais de toute façon, si x<=200 alors (200-x)>0 et si (x>=200) alors (200-x)<0... donc d'une part pas besoin d'utiliser fabs alors qu'on connaà®t le signe de la différence... et en plus si on enlève fabs et applique le signe nous-même, ça donne la même affectation. Donc on peut se contenter de :
    x += (200-x)/100;<br />y += (300-y)/50;
    

    Quand même plus compact que les 23 lignes... et évite des if et des fabs consommateurs pour rien !!
  • schlumschlum Membre
    02:28 modifié #5
    Ah OK, c'est pour qu'un point se rapproche d'un autre !

    Mais t'es au courant qu'avec cette technique il va s'en approcher de plus en plus lentement ?

    Si au début il est à  une distance de 100, il sera au pas suivant à  99 ; ensuite à  98.01... à  chaque fois le pas d'approche sera plus petit et la convergence est très très lente !
  • schlumschlum Membre
    mars 2009 modifié #6
    dans 1237035669:

    Et pourquoi en écrire 8 au lieu de 2 ?


    Parce que je pensais que condition <= était erronnée donc j'ai séparé les cas.

    dans 1237035669:

    Déjà  attention schlum, tes conditions ne sont pas exclusives... dans le cas où x est précisément égal à  200, tu vas passer dans les 2 premières conditions au lieu d'une seule.


    Ce qui n'est pas dramatique en soi puisque ça ajoute 2 fois 0  :P
    Mais j'avais pas compris ce qu'il voulait faire...
    Ni l'intérêt des fabs en fait... Si x<=200, fabs(((200-x)/100)) = (200-x)/100
  • CeetixCeetix Membre
    02:28 modifié #7
    les fabs c'etait pour certains cas où au lieu de se rapprocher les rectangles s'éloignaient.
    En effet passer de 23 à  2 lignes....  :-\\
    Et oui c'est pour se rapprocher de plus en plus lentement, histoire de donner un petit effet .
  • schlumschlum Membre
    02:28 modifié #8
    dans 1237036915:

    les fabs c'etait pour certains cas où au lieu de se rapprocher les rectangles s'éloignaient.


    J'ai du mal à  voir comment ils auraient pu s'éloigner en se rapprochant d'1/100e de la distance... mais bon, passons  :P
    C'est quoi le problème en fait ?
  • CeetixCeetix Membre
    02:28 modifié #9
    Je suis pas fou quand même, ça s'éloignait bien ^^.
    Oui le problème c'est que c'est super chouette pour un rectangle mais j'aimerai le faire pour plus, et ne pouvoir en bouger qu'un seul (celui que je selectionne) . Et là  je suis un peu perdu (voir beaucoup ...)
  • schlumschlum Membre
    02:28 modifié #10
    Ben... Pour les cas où ça s'éloignait, il suffisait d'inverser le signe  :P

    Si x>200, x-200>0
    Si x<200, x-200<0

    Sinon, pour en gérer plusieurs, il suffit d'en instancier plusieurs et dans le drawrect de sauter les tests si ce n'est pas celui sélectionné.
  • AliGatorAliGator Membre, Modérateur
    02:28 modifié #11
    Ou plutôt de garder un pointeur sur celui sélectionné, plus simple si ce sont des instances d'objets, non ?
    Enfin ça dépend de son archi et de son use case mais bon moi c'est comme ça que je gère mon "objet actuellement sélectionné" quand j'ai ce genre de trucs à  faire ;)
  • CeetixCeetix Membre
    02:28 modifié #12
    Oui bon roooo ^^ ...

    Oui mais imaginons qu'il y ai 100 rectangles .... Ca commence à  faire un peu beaucoup non ?
  • schlumschlum Membre
    02:28 modifié #13
    dans 1237039189:

    Ou plutôt de garder un pointeur sur celui sélectionné, plus simple si ce sont des instances d'objets, non ?
    Enfin ça dépend de son archi et de son use case mais bon moi c'est comme ça que je gère mon "objet actuellement sélectionné" quand j'ai ce genre de trucs à  faire ;)


    Ben... Et tu redessines comment les autres (même s'ils ne bougent pas !) ?  :o
    :P
  • schlumschlum Membre
    02:28 modifié #14
    dans 1237039318:

    Oui bon roooo ^^ ...

    Oui mais imaginons qu'il y ai 100 rectangles .... Ca commence à  faire un peu beaucoup non ?


    Quoi dessiner 100 rectangles, tu penses que ça va fatiguer la carte graphique ? Tu rigoles j'espère  :)
  • CeetixCeetix Membre
    02:28 modifié #15
    Ce sont des super rectangle tip top c'est pour ca :D
    Mais comment tu fais savoir lequel est sélectionné? Car là  j'ai bien mon tableau de rectangle mais après ...
  • schlumschlum Membre
    02:28 modifié #16
    Ben tu gardes un pointeur ou un indice sur celui qui bouge...  ???
  • CeetixCeetix Membre
    02:28 modifié #17
    Oui pour après ma selection mais pour selectionné ?
    Car ok, après l'avoir selectionné je lui fou un indice qui dira que c'est lui qu'il faut bouger. Mais aavnt ?
  • AliGatorAliGator Membre, Modérateur
    02:28 modifié #18
    mais après... bah tu recherches sur le forum, doit y avoir 3 ou 4 membres qui développent des trucs similaires genre plateau de jeu avec des formes qui se baladent (ou pas) dessus, donc on a déjà  abordé la question de la détection du clic...

    Si ce sont des NSView, et que userInteractionEnabled=YES, ce sont elles qui vont recevoir le Touch, sinon bah tu boucles sur tes formes et tu utilises CGRectContainsPoint pour tester l'appartenance du point du Touch au rectangle, ou CGPathContainsPoint si c'est un CGPath plus complexe qu'un CGRect...
  • CeetixCeetix Membre
    02:28 modifié #19
    Ok je vais chercher et voir tout ça !
    Merci
  • CeetixCeetix Membre
    02:28 modifié #20
    Il faut que je refasse tou non? Car là  je suis en NSRect. Il faut donc passer par CGRect ou context?
    D'ailleur, je sais comment coloriser un context mais un CGRect je vois pas ...
  • CeetixCeetix Membre
    02:28 modifié #21
    Bon j'ai tout refais.
    Je créer un NSObject Rectangle avec une method d'initialisation d'un rectangle.
    Puis dans ma NSView et dans drawRect je fais :

    <br />for(int i = 0 ; i&lt;2; i++)<br />	{<br />		Rectangle *objet = [[Rectangle alloc] initWhithX:x Y:y H:20 L:20 pX:x pY:y select:NO];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // x y sont des variables globales<br />		[tableauRect addObject:objet]; // c&#39;est un MutableArray que j&#39;initialise dans initWithFrame<br />		x +=30;<br />	}<br />
    


    Sans ajouter a mon tableau tout marche, mes deux rectangles s'affiches.
    Si je fais mon addObjet à  mon tableau alors l'app crash sans même dessiner et aucun message d'erreur spécifique n'apparait à  part : " EXC_BAD_ACCESS ".

    Je comprends pas où est mon erreur :s
  • schlumschlum Membre
    02:28 modifié #22
    Déjà , il y a une erreur de leak... "objet" ne sera jamais libéré...
    Ensuite, il y a sans doute aussi une erreur de mémoire... il faudrait voir commetn est initialisé "tableauRect", mais je parie qu'il est déjà  libéré au niveau de ce code !
  • CeetixCeetix Membre
    02:28 modifié #23
    il faut le libérer quand? Dans un -(void)dealloc ?
    Sinon j'ai initialiser ainsi :tableauRect = [[NSMutableArray alloc] init];
    Il faudrait faire un initWithObjects plutôt?
  • schlumschlum Membre
    02:28 modifié #24
    Non, faut faire un release dessus après l'avoir ajouté au NSMutableArray.
    Dur dur pour la mémoire aussi  :P

    "addObject:" fait un "retain" sur les objets.

    "[[NSMutableArray alloc] init]" c'est OK... À voir si la variable n'est pas écrasée après...
  • GreensourceGreensource Membre
    02:28 modifié #25
    Coucou! Juste pour dire que c'est cool qu'on ai à  peu près le même problématique, on peut s'entre-aider comme ça.

    Merci à  vous trois particulièrement (schlum,Ali et Philippe), c'est bien sympa de prendre du temps pour nous aider!
  • AliGatorAliGator Membre, Modérateur
    02:28 modifié #26
    dans 1237060715:

    Il faut que je refasse tou non? Car là  je suis en NSRect. Il faut donc passer par CGRect ou context?
    D'ailleur, je sais comment coloriser un context mais un CGRect je vois pas ...
    Non non avec NSRect ça marche aussi, c'est juste pas le même nom de méthode (c'est parce que je programme bcp sur l'iPhone en ce moment qui utilise des CGRect là  où l'API OSX utilise des NSRect, mais c'est pareil en somme)

    Tu trouveras sans doute ton bonheur dans cette page de la doc (que j'ai toujours de mal à  retrouver à  chaque fois d'ailleurs, je la trouve bien cachée), n particulier cette fonction autour de NSRect.
  • CeetixCeetix Membre
    02:28 modifié #27
    Lol merci Ali, je suis quand même passé en CGContextRef etc ... C'est pas grave? Ca à  l'air de marcher aussi très bien sauf pour mon tableau meme quand je fais un release de objet apres l'avoir ajouté à  tableauRect.

    Et je suis en total accord avec Greensource . Merci beaucoup ;)
  • CeetixCeetix Membre
    02:28 modifié #28
    BOn je suis repassé en NSRect, mais tjs ce probleme de tableau ...
    Voici comment je m'en sers.

    <br />- (id)initWithFrame:(NSRect)frame {<br />&nbsp; &nbsp; self = [super initWithFrame:frame];<br />&nbsp; &nbsp; if (self) {<br />&nbsp; &nbsp; &nbsp; &nbsp; x = 10;<br />		y = 10;<br />		tableauRect = [[NSMutableArray alloc] init];<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return self;<br />}<br /><br />- (void)drawRect:(NSRect)rect {<br />	<br />	for(int i = 0 ; i&lt;2; i++)<br />	{<br />		<br />		Rectangle *objet = [[Rectangle alloc] initWhithX:x Y:y H:20 L:20 pX:x pY:y select:NO];<br />		[tableauRect addObject:objet];<br />		[objet release];<br /><br />		x +=30;<br />	}<br />}<br /><br />
    

    La compilation se fait bien mais quand je run ma fenetre n'apparait même pas :s
  • schlumschlum Membre
    02:28 modifié #29
    Euh... tu tiens vraiment à  allouer tes objets et les mettre dans le tableau à  chaque fois que "drawRect:" est appelé ?  ???
  • CeetixCeetix Membre
    02:28 modifié #30
    Bah, apprès je m'en sert dans d'autres méthodes pour modifier un des objets donc j'ai besoin d'acceder à  tous les objets.
  • schlumschlum Membre
    02:28 modifié #31
    dans 1237128128:

    Bah, apprès je m'en sert dans d'autres méthodes pour modifier un des objets donc j'ai besoin d'acceder à  tous les objets.


    Nan, mais t'es conscient qu'à  chaque appel de "drawRect", tu vas ajouter deux nouveaux objets à  la liste ?
    À chaque "setNeedsDisplay:", hop deux nouveaux objets...
Connectez-vous ou Inscrivez-vous pour répondre.