2013-05-12 7 views
14

Sai quell'effetto quando trascini un oggetto dal dock e quel cursore di trascinamento della nuvola appare e quando lo lasci andare scompare con un effetto poof? Allo stesso modo, in Xcode quando si trascina un punto di interruzione al di fuori del numero di linea, si verifica lo stesso errore.Trascina per eliminare l'elemento

Vorrei implementare lo stesso effetto nella mia applicazione ma non trovo la strada giusta.

Ho un discendente NSImageView per implementare i protocolli NSDraggingSource e NSDraggingDestination. Ho diverse istanze di questa vista che consentono di trascinare il loro contenuto tra gli altri (un'operazione di copia si svolge in questo scenario, ma questo è rilevante solo per mostrare che ho drag'n drop impiantato e pienamente funzionante per le attività standard).

Ora, quando trascino un'immagine dalla sua vista in qualsiasi posizione (eccetto un'altra istanza di vista) Voglio che l'operazione di cancellazione abbia luogo in caduta. Tuttavia, l'operazione di trascinamento è completamente controllata dalla vista di destinazione. Potrei riuscire a farli rispondere nel modo che voglio (anche se questo sarebbe un sacco di lavoro), ma fallisce completamente se sto trascinando fuori dalla mia applicazione.

Se ho potuto ottenere l'operazione di eliminazione di trascinamento ho potuto gestire questo però problemi dalla:

- (void)draggedImage: (NSImage *)image 
      endedAt: (NSPoint)screenPoint 
      operation: (NSDragOperation)operation 
{ 
    if (operation == NSDragOperationDelete) { 
     NSRect rect = [self.window convertRectToScreen: [self convertRect: self.frame fromView: nil]]; 
     NSShowAnimationEffect(NSAnimationEffectPoof, rect.origin, self.bounds.size, nil, nil, NULL); 
    } 
} 

Ho provato già per impostare il cursore di eliminazione simili:

- (void)draggingSession: (NSDraggingSession *)session 
      movedToPoint: (NSPoint)screenPoint 
{ 
    if (!NSPointInRect(screenPoint, self.window.frame)) { 
     [[NSCursor disappearingItemCursor] set]; 
    } 
} 

(per semplicità questo è per l'intera windw al momento). Questo funziona fintanto che non colpisco il desktop o una finestra di ricerca. In inizia a sfarfallare, probabilmente perché il Finder imposta contemporaneamente il proprio cursore di trascinamento. Non ha alcun effetto quando colpisco il molo. Questo accade anche quando definisco il mio tipo di dati a scacchiera.

Inoltre, qualsiasi altra visualizzazione abilitata per il rilascio nella mia applicazione accetterà ancora i miei dati di trascinamento (ad esempio NSTextView) che non voglio che accada (sto scrivendo un NSURL al pannello di trascinamento con uno schema personalizzato).

Aggiornamento:

Sono venuto inoltre a pochi passi. Come Peter già indicato, è essenziale per gestire draggingSession:sourceOperationmaskForDraggingContext: che sembra così nel mio codice:

- (NSDragOperation)  draggingSession: (NSDraggingSession *)session 
    sourceOperationMaskForDraggingContext: (NSDraggingContext)context; 
{ 
    switch(context) { 
     case NSDraggingContextOutsideApplication: 
      return NSDragOperationDelete; 
      break; 

     case NSDraggingContextWithinApplication: 
     default: 
      return NSDragOperationDelete | NSDragOperationMove; 
      break; 
    } 
} 

Questo risolve 2 problemi: 1) fuori dell'applicazione l'operazione di trascinamento non è accettata a tutti, 2) Mantiene tutte le viste standard dall'accettare anche questa operazione (poiché NSOutlineView, NSTextView ecc. non gestiscono le operazioni di trascinamento fornite). Inoltre, ho creato un proprio tipo di datasheet, ma questo non sembra essere necessario. Eppure è più chiaro avere una propria.

Sfortunatamente, l'uscita dal mio discendente NSImageView (sia all'interno che all'esterno dell'applicazione) non mi dà NSDragOperationDelete in draggedImage:endedAt:operation: (cosa ho specificato sopra) ma NSDragOperationNone. Inoltre il cursore di trascinamento quando si sposta il mouse all'esterno dell'applicazione è quello non consentito, non quello che scompare. Quindi, se qualcuno potesse risolvere queste due cose, lo accetterei come risposta alla mia domanda.

+0

Si prega di modificare la domanda per mostrare l'implementazione del metodo di trascinamento del 'draggingSession: sourceOperationMaskForDraggingContext:'. –

risposta

-3

È possibile utilizzare il seguente comando per rendere il puff appare in corrispondenza della posizione del mouse:

NSShowAnimationEffect(NSAnimationEffectPoof, [NSEvent mouseLocation], NSZeroSize, NULL, NULL, NULL); 

Vedere la Application Kit Functions Reference per ulteriori informazioni.

+0

Non solo non ho chiesto come eseguire l'effetto poof che ho già nella mia domanda. –

+0

@ MikeLischke: scusa, ho frainteso la tua domanda. Puoi essere più specifico su ciò che stai cercando di ottenere? – MrAsterisco

+0

Hmm, penso di spiegare abbastanza bene cosa sto cercando. L'effetto drag-out-to-remove dal dock è abbastanza noto e la mia domanda riguarda come farlo nella mia app. –

2

Potrebbe esserci un modo meno hacky per farlo, ma posso pensare a una possibilità: una volta iniziato il trascinamento, creare una finestra trasparente, senza bordi, la dimensione del desktop da essere una destinazione di trascinamento fittizio. Potrebbe essere necessario chiamare lo -setIgnoresMouseEvents: con NO per consentirgli di ricevere il rilascio anche se è trasparente. Dovrai anche impostare il livello della finestra sopra la barra dei menu (NSMainMenuWindowLevel + 1) per assicurarti che i trascinamenti verso la barra dei menu o il Dock siano ancora intercettati dalla tua finestra.

Come destinazione di trascinamento, questa finestra dovrà verificare se una delle viste dell'immagine è sotto il cursore. È possibile utilizzare +[NSWindow windowNumberAtPoint:belowWindowWithWindowNumber:] per trovare la finestra sotto la finestra di overlay trasparente che si trova sotto il cursore. Quindi usa -[NSApplication windowWithWindowNumber:] per determinare se è una delle finestre della tua app e, in tal caso, chiama -[NSView hitTest:] nella sua vista del contenuto (convertendo le coordinate del cursore come appropriato) per trovare la vista. È quindi possibile inoltrare i metodi NSDraggingDestination a quella vista come desiderato.

+0

Hmm, ho una configurazione di 3 monitor. Altri certamente usano impostazioni diverse. Ciò significa che dovrei controllare anche tutti i monitor. Inoltre, quando si trascina fuori dal dock, è comunque possibile cambiare app con ⌘ + Tab ecc. Pertanto, in definitiva, non utilizzano una finestra di copertura. –

+0

Dovresti fare in modo che la tua finestra copra tutto il desktop, sì. Non è difficile. Basta scorrere su '[schermi NSScreen]', ottenere il '-frame', e unirli insieme usando' NSUnionRect() '. Una finestra su "NSMainMenuWindowLevel' + 1 non coprirà il commutatore di applicazioni. Non sono sicuro in che senso ti aspetti che Command-Tab non funzioni. Inoltre, il Dock non consente in realtà il rilascio da nessun'altra parte, quindi forse non usa il drag-and-drop reale. Forse usa solo il tracciamento del mouse e imposta il cursore. Ho un'app di destinazione di trascinamento test e non riceve '-draggingEntered:' per un trascinamento dal Dock su 10.6. –

+0

In realtà, questa è un'idea interessante. Mentre si trascina fuori dal dock, posso fare tutto con il sistema che non richiede un clic sinistro (ad esempio, posso fare clic con il pulsante destro del mouse o fare clic con il tasto destro del mouse su Exposé, elementi del menu trigger ecc.). Molto simile per il trascinamento dei breakpoint in XCode. Sei molto vicino a guadagnare le munificenze. Dammi solo una soluzione funzionante nella tua risposta. –

2

La mia ipotesi è che NSDragOperationDelete riguardi solo il trascinamento/rilascio per il Cestino del Cestino e nient'altro.

NSDragOperationGeneric dovrebbe essere una soluzione migliore. Fare attenzione a non mescolare i metodi, se si sta andando il percorso 10.7, preferiscono:

-(void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation 
+0

Ecco come lo faccio al momento. Il problema è che ottengo sempre un NSDragOperationNone (tranne per la mia vista personale dove ottengo le operazioni di trascinamento con cui ho iniziato). Come ho detto in un altro commento, dalle mie osservazioni penso davvero che il dock non usi il normale drag/drop ma un semplice approccio di cattura del mouse. Durante l'operazione di "trascinamento" puoi interagire completamente con il resto del sistema (eccetto il pulsante sinistro del mouse). –

+0

Sì, è assolutamente possibile. Sembra che sia una combinazione di un minimo-timer e una discriminazione a distanza, sai proteggere dalle cadute accidentali. Niente di troppo elegante – Nightbirdsevolve

+0

Ho appena controllato, anche durante una normale operazione di trascinamento è possibile fare clic destro e aprire un menu e tutto il resto. Quindi ora penso che sia ancora normale trascinare nella dock (non me l'aspettavo, quindi non ho mai controllato). Ha anche senso quando si considera che è necessario dd per spostare le voci nel dock. Quindi torniamo al punto 1 e abbiamo bisogno di una risposta su come il dock gestisce il cursore di trascinamento. Immagino dragSession: moveToPoint: svolge un ruolo importante, quindi non dovrebbe essere così difficile da risolvere. Voglio solo ottenere qualcosa per la mia taglia ;-) –

0

OS X 10.7 o superiore:

- (void) draggingEnded: (id<NSDraggingInfo>) aInfo { 
    /*! Delete the current leaf if it is no longer represented in the subviews. */ 
    RETURN_IF (, NSNotFound != [self.visibleLeafs indexOfObject: iSelectedControl.representedObject]); 
    iIgnoreLeafsObservation = YES; 
    [self.leafs removeObject: iSelectedControl.representedObject]; 
    iIgnoreLeafsObservation = NO; 
} 

questo presuppone che si è visivamente rimosso l'oggetto già. Puoi anche impostare un flag durante il draggingEntered: e draggingExited: per indicare se la sessione di trascinamento è stata l'ultima all'interno o all'esterno di self.

In questo programma, leafs è la raccolta effettivamente osservata mentre visibleLeafs è una raccolta simulata dell'oggetto rappresentato di ciascun controllo visibile. Altri sovraccarichi di NSDraggingDestination presentano ciò che accadrà visivamente prima che accada realmente.

+0

Hmm, questo codice è solo un approccio diverso per aggirare l'operazione NSDragOperationDelete mancante. Non migliora davvero la soluzione alternativa che ho attualmente. –