NSCursor pendant un mouseDragged

AliGatorAliGator Membre, Modérateur
février 2006 modifié dans API AppKit #1
Bonsoir tout le monde :)

Alors voilà  : j'ai une NSView (sous-classée en MyView) qui est encapsulée dans une NSScrollView (dans IB : Layout --> Make subviews of --> Scroll View).
Au passage : MyView sert à  afficher une NSImage, donc je change sa frameSize quand je change la NSImage (juste avant mon setNeedsDisplay:YES).

J'ai rajouté une possibilité de scroller ma MyView quand je fais un cliquer-glisser dessus (surcharge de mouseDown pour mémoriser dans une v.i. la position du clic, et de mouseDragged pour faire un scrollPoint)

Maintenant j'aimerais mettre le openHandCursor dès que MyView est survolée (mouseEntered) ou au moins cliquée (mouseDown)

Mais j'ai eu beau essayer plein de trucs, j'arrive jamais à  ce que je veux  :'(
  • J'ai commencé par mettre [tt][[NSCursor openHandCursor] push][/tt] dans le mouseDown et le [tt][NSCursor pop][/tt] dans mouseUp, mais bien que quand je clique ça mette bien la main, dès que je bouge la souris pour commencer mon drag c'est le arrowCursor qui revient.  ??? >:(
  • J'ai essayé avec un [tt][[NSCursor openHandCursor] set][/tt] dans mouseDown (ou mouseEntered) et dans mouseDragged (et [tt][[NSCursor arrowCursor] set][/tt] dans mouseUp (ou mouseExited)) et c'est le mieux que j'ai réussi, ça marche pas trop mal, mais dès que j'arrête de bouger la souris, arrowCursor revient (même si je relâche pas le bouton). Et la main ne se remet que quand je recommence à  bouger... :'(
  • Alors j'ai enlevé mes "set" et mes "push/pop" et j'ai essayé avec [tt]addCursorRect:[self bounds]cursor:[NSCursor openHandCursor][/tt] dans mon initWithFrame de MyView mais sans plus de succès. :-\\
  • J'ai même essayé [tt]discardCursorRects[/tt] + [tt]addTrackingRect:owner:userData:assumeInside:[/tt] mais sans succès non plus.  :crackboom:-


Bref je commence à  saturer à  essayer plein de trucs alors que ça doit être tout con.
Le mieux pour l'instant c'est le "set" sur le openHandCursor, repris dans le mouseDragged... mais du coup ça "flashouille" entre la main et la flèche...

HELP !  :why?:

Réponses

  • Eddy58Eddy58 Membre
    18:58 modifié #2
    Ca me rappelle un code d'exemple ça, qui je pense se rapproche de ton cas. Tu le trouveras ici, exemple Grab-Scrolling. :)
  • BruBru Membre
    18:58 modifié #3
    A mon avis, il faut empêcher une session de dragging de débuter (ce qui provoque le changement du curseur).

    Essaie d'implanter dans ta vue la méthode draggingSourceOperationMaskForLocal: en retournant la valeur NSDragOperationNone.

    .
  • fouffouf Membre
    18:58 modifié #4
    En fait, je suis pas bien sûr d'avoir compris ta question. Alors, comme je fais un truc qui ressemble dans Geodes (changement des coordonnées de l'origine après un drag et aussi glissé d'un objet), je te file le code :

    <br />- (void)resetCursorRects<br />{	<br />	int tool = [_toolsController selectedTool];<br />	if(tool == 0 || tool == 1 || tool == 2 || tool == 3 || tool == 4 || tool == 8){ // test de l&#39;outil en cour<br />		_cursor = [NSCursor crosshairCursor]; //selection du curseur<br />	}else if (tool == 6){ // outil de déplacement (la main)<br />		if(_isDragging) // entrain de faire un glisser<br />			_cursor = [NSCursor alphaClosedHandCursor]; //même chose que closedHandCursor<br />		else<br />			_cursor = [NSCursor alphaOpenHandCursor]; //même chose que openHandCursor<br />	}else if (tool == 7){<br />		_cursor = [NSCursor pointingHandCursor];<br />	}else if (tool == 5){<br />		_cursor = [NSCursor navigationCursor];<br />	}<br />	[self addCursorRect:[self visibleRect] cursor:_cursor]; // mise en place du curseur<br />	[_cursor setOnMouseEntered:YES];<br />}<br /><br />- (void)discardCursorRects<br />{<br />	if(_cursor)<br />		[self removeCursorRect:[self visibleRect] cursor:_cursor]; // destruction du curseur<br />}
    


    Voila, normalement, ces méthodes sont appelées automatiquement.

    Puis dans le mouseDown: il faut que tu mettes à  jour les curseurs pour que la mimine soit fermée et donc, tu change _isDragging et tu invalide les curseurs, d'où :
    <br />_isDragging = YES;<br />[[self window] invalidateCursorRectsForView:self];
    


    Et enfin, pour que la main redevienne ouverte dans le mouseUp

    - (void)mouseUp:(NSEvent *)e<br />{<br />	...<br />	if(_isDragging){<br />		_isDragging = NO;<br />		[[self window] invalidateCursorRectsForView:self];<br />	}<br />	...<br />}
    


    Voila, je ne sais pas si ca répond à  ta question, mais c'est ce que je fais dans Geodes ;)
  • AliGatorAliGator Membre, Modérateur
    18:58 modifié #5
    Merci de toutes vos réponses, je tâche de tester ça ce WE (je n'aurais pas le temps avant dimanche je pense)

    Bru, pour donner plus de précisions :
    Ce n'est pas un drag&drop de mon image qui est fait et que je veux faire. Juste pouvoir déplacer ma vue dans sa scrollview par cliquer-glisserc ce qui fonctionne déjà  d'ailleurs. Et ce que le curseur de la main est sensé indiquer d'un seul coup d'oeil.
    A moins que tu ne veuilles insinuer que Cocoa pense que je veuille faire un drag&drop, mais que comme je n'ai pas implémenté les méthodes pour le faire, bien sûr il ne le fait pas, mais le curseur est quand même affecté ? ???

    Je regarde l'exemple du Grab-Scrolling (qui correspond à  ce que j'ai implémenté en effet) et le code de fouf dès que j'ai un peu de temps à  consacrer à  Xcode  ;)

    Merci de vos pistes  :o 8)
  • LeChatNoirLeChatNoir Membre, Modérateur
    février 2006 modifié #6
    Ben je relance le sujet parce que j'ai le même pb...

    En fait, je fais mon petit contrôle genre poignée pour redimensionner mes vues.

    J'ai la fonction resetCursor... dans laquelle je dis que le curseur doit être le curseur de redimensionnement lorsque la souris passe dessus. Ca roule.

    Mais quand je drag, tant que le curseur reste dans le contrôle, ca fonctionne, mais dès qu'il en sort (par exemple, si je vais plus vite que le redimensionnement ou si j'ai atteint la taille mini), il redevient la flèche.

    J'ai tenté de virer les rectangles de tracking, pas mieux.
    De forcer le curseur dans MouseDragged, même  phénomène qu'Ali (clignote).

    En fait, on dirait que le drag reset le curseur...
    Pourtant, dans RBSplitView, le curseur ne change pas mais j'ai du mal a analyser le code parce qu'il n'utilise pas mouseDragged. Au lieu de ça, il fait tout dans MouseDown avec ce genre de boucle :
    <br />while ((theEvent = [NSApp nextEventMatchingMask:NSLeftMouseDownMask|NSLeftMouseDraggedMask|NSLeftMouseUpMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:YES])&amp;&amp;([theEvent type]!=NSLeftMouseUp)) {<br />// Set up a local autorelease))<br />
    


    J'ai même tenté un addCursorRect sur toute la fenêtre lors de la détection du drag... sans succès...

    Bref, y a un truc qui m'échappe avec le mouseDragged et les curseurs...  :why?: us :-)

    J'ai regardé le code de Eddy58 mais il s'agit d'un drag particulier dans une ScrollView (ca répondra à  Ali à  mon avis)) et une fonction liée au NSCursor gère ça bien.

    Le code de Fouf me semble bien aussi mais je pense que même pb si on sort de la vue...
  • AliGatorAliGator Membre, Modérateur
    février 2006 modifié #7
    dans 1140132334:

    Ca me rappelle un code d'exemple ça, qui je pense se rapproche de ton cas. Tu le trouveras ici, exemple Grab-Scrolling. :)
    Bon ben je viens d'essayer, c'est enfantin... encore fallait-il utiliser la bonne méthode :D
    Trouvée dans cet exemple justement. Il faut donc mettre dans mouseDown et mouseUp de la View, la ligne [tt][(NSScrollView*)[self superview] setDocumentCursor:curs];[/tt] :
    - (void)mouseDown:(NSEvent*)evt<br />{<br />	clickLoc = [evt locationInWindow];<br />	[(NSScrollView*)[self superview] setDocumentCursor:[NSCursor closedHandCursor]];<br />}<br />- (void)mouseDragged:(NSEvent*)evt<br />{<br />	NSPoint loc = [evt locationInWindow];<br />	NSPoint delta = NSMakePoint(clickLoc.x - loc.x, clickLoc.y - loc.y);<br />	NSPoint oldPos = [self visibleRect].origin;<br />	NSPoint newPos = NSMakePoint(oldPos.x + delta.x , oldPos.y + delta.y);<br /><br />	[self scrollPoint:newPos];<br />	clickLoc = loc;<br />}<br />- (void)mouseUp:(NSEvent*)evt<br />{<br />	[(NSScrollView*)[self superview] setDocumentCursor:[NSCursor openHandCursor]];<br />}
    
    Ce qui modifie bien le curseur pendant le déplacement.
    (J'ai mis le code du mouseDragged aussi si ça en intéresse, mais il n'y a pas besoin de toucher au curseur dedans comme vous le voyez)


    Maintenant il faut aussi rajouter cette ligne magique lorsque la vue est créée.
    J'ai donc mis la ligne magique dans le initWithFrame de MyView mais ça n'a pas marché... mais sans doute parce que ma vue à  l'origine est vide et se redimentionne que lorsque j'ai mon image.

    Donc j'ai mis la méthode qui calcule mon image avant le [tt]setNeedsDisplay[/tt] :
    // code de calcul de l&#39;image &quot;img&quot;<br />// ...<br /><br />// draw it<br />[mapView setFrameSize:[img size]];<br />[(NSScrollView*)[mapView superview] setDocumentCursor:[NSCursor openHandCursor]];<br />[mapView setNeedsDisplay:YES];
    
    (où mapView est un outlet vers ma vue bien sûr)

    Donc 3 occurences de [tt]setDocumentCursor[/tt] et c'est fait :) Fallait juste trouver que c'est par setDocumentCursor qu'il faut passer :)
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:58 modifié #8
    Salut,
    De mon côté, je ne peux utiliser cette méthode car je ne suis pas dans une NSScrollView...

    J'ai trouvé une solution que je vous avais déjà  donné :
    while ((theEvent = [NSApp nextEventMatchingMask:NSLeftMouseDownMask|NSLeftMouseDraggedMask|NSLeftMouseUpMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:YES])&&([theEvent type]!=NSLeftMouseUp)) {
    // Set up a local autorelease))

    Dans le mouseDown, on enclenche une boucle et on gère les évènements jusqu'au mouseup.

    Dans ce cas, ça fonctionne bien et le curseur est constant et bien celui que je désire.

    Une question cependant : mon appli sera multi thread plus tard. Il y aura des actions qui se dérouleront en parallèle et qui mettront à  jour une autre vue.

    Si je fais un drag avec une boucle de ce type, ca va tout bloquer non ? Je ne pourrai plus observer le boulot des autres thread ?

  • UniXUniX Membre
    18:58 modifié #9
    Salut,

    Je réouvre ce sujet car j'ai un problème parfaitement similaire à  celui de LeChatNoir.
    Par contre, je ne comprends pas bien ta technique .... Tu peux m'en dire plus ?
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:58 modifié #10
    Salut,

    ouh la la, ca me parait loin tout ça ! J'ai pas retouché au code depuis ... pffff....
    Je me rappelle vaguement de ce pb. J'avais réussi à  le résoudre mais malheureusement, j'ai ensuite utilisé les possibilités de RBSplitView (qui permet de définir une poignée de drag).

    Donc tu peux éventuellement chercher dans le code de Pom'F mais pas dans les dernières versions. La version juste avant celle ou j'ai revue l'utilisation de RBSplitView (j'avais des commentaires donc tu devrais t'y retrouver).

    A+ et bon courage !

    J'en profite pour passer un ch'tit bonjour à  tous les habitués et m'excuses de ne plus participer... Vraiment désolé mais je consacre mon temps à  d'autres choses... J'espère y revenir un jour mais quand je vois la vitesse ou ça va, ça me fait peur (iPhone, Leopard, Core Animation, etc...).

    Continuez bien et à  bientot !
  • UniXUniX Membre
    18:58 modifié #11
    OK LeChatNoir, je vais essayer de regarder tout ça.

    Je vais quand même décrire mon problème :
    J'ai une vue perso. je voudrais que lorsque je rentre dans une zone de la vue, le curseur se change en main ouverte. Pour ça c'est OK avec :
    NSCursor *main = [[NSCursor alloc]initWithImage:[NSImage imageNamed:@&quot;mainOuverte&quot;] hotSpot:NSMakePoint(8,8)];<br />[self discardCursorRects];<br />[self addCursorRect:cadreRouge cursor:main];<br />[main release];
    


    Après, et c'est là  que ça se complique, je voudrais que lorsque je clique et que je fais un drag, le curseur devienne la main fermée, et que lors du mouseUp il redevienne la main ouverte.
    Comme Ali à  l'époque, j'ai un peu tout essayé sans réussir à  trouver la bonne solution. Et pour faciliter la chose, la page traitant de ce sujet dans la doc Apple n'existe plus ...

    Attention : ma vue n'est pas dans une NSScrollView ou NSClipView, donc la méthode setDocumentCursor: n'est pas utilisable ...
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:58 modifié #12
    ben ma solution résidait dans la surcharge de mouseDown avec une boucle décrite plus haut.
    Fouille dans le code de RBSplitView.
    A+
Connectez-vous ou Inscrivez-vous pour répondre.