Cocoa NSView subview blocking drag/drop

Discussion in 'Mac Programming' started by Avicenna, May 4, 2011.

  1. macrumors member

    Joined:
    Jul 16, 2009
    #1
    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.
     
  2. macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #2
    Try adding this to your NSView subclass
    Code:
    - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
    {
      return NSDragOperationCopy;
    }
    
     
  3. macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #3
    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.
    Code:
        [[NSColor redColor] setFill];
        [NSBezierPath fillRect:[self bounds]];
    
     

    Attached Files:

Share This Page