PDA

View Full Version : Cocoa NSView subview blocking drag/drop




Avicenna
May 4, 2011, 11:39 PM
I have an NSView subclass which registers for drag files in init method like this:

[self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];

The drag drop works perfectly fine, but if I add a subview to this view with the exact same frame, it doesn't work any more. My guess is that the subview is blocking the drag event to go to super view. How can I avoid that? Thanks

Also, when I am dragging, my cursor doesn't change to the "+" sign like with other drags in Finder or other applications, how can I do that? Thanks again.



jiminaus
May 4, 2011, 11:55 PM
Also, when I am dragging, my cursor doesn't change to the "+" sign like with other drags in Finder or other applications, how can I do that? Thanks again.

Try adding this to your NSView subclass

- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
{
return NSDragOperationCopy;
}

jiminaus
May 5, 2011, 08:08 AM
I have an NSView subclass which registers for drag files in init method like this:

[self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];

The drag drop works perfectly fine, but if I add a subview to this view with the exact same frame, it doesn't work any more. My guess is that the subview is blocking the drag event to go to super view. How can I avoid that? Thanks


So after lots of playing with bowels of the Cocoa event system, what I've discovered is that the whole of a drag and drop operation happens within the window server. This includes determining which view is under the mouse and therefore the target of the d'n'd operation. The target application doesn't get any events or messages, so it's impossible for your application to change this determination.

But the behaviour is strange. If a subview never registers dragged types, it is completely transparent to the window server's process for determining the target view. In this case, the super view will remain the d'n'd target even if the mouse moves over the subview.

If a subview ever registers dragged types, it will become the d'n'd target when the mouse moves over it. Even sending unregisterDraggedTypes to the subview doesn't stop this. The super view will still be sent a draggedExited message and will stop being the d'n'd target even though the subview cannot accept any type of d'n'd operation.

So the "best" solution I came up with is to put a glass view over the top of your super view and subview. A glass view is an NSView subclass who's drawRect: does nothing and who's hitTest: always returns nil. Move the drag'n'drop code from your super view to the glass view.

You need to be careful that the glass view has the highest Z order. In Interface Builder, it needs to be at the bottom of the document tree. See the attached image. The "Glass Drop View" is positioned over the top of the "Drop Target View". You'll probably need to use the cursor keys to move it over without becoming embedded as a subview.

To confirm, put something like the following into your glass view's drawRect:. Then your super view should be covered by red. If not, then the glass view is behind your super view, not in front of it.

[[NSColor redColor] setFill];
[NSBezierPath fillRect:[self bounds]];