mouseDragged events get stolen by another view
I have several views of class MyView
(subclass of NSView
) inside another NSView
. MyView
implements -mouseEntered:
, -mouseExited:
, -mouseDown:
, -mouseDragged:
, and -mouseUp:
.
Almost always, when a MyView
receives a mouse-down event, all subsequent mouse-dragged events are received by the same MyView
until the next mouse-up event. Even if the cursor goes outside of the MyView
. That is the expected behavior.
Occasionally, a MyView
will receive a mouse-down event, but will only receive mouse-dragged and mouse-up events while the cursor remains inside the MyView
. If the cursor moves onto a different MyView
, then that MyView
starts receiving mouse-dragged events (without first receiving a mouse-down event) and can receive the subsequent mouse-up event.
In case it matters, the mouse-down event creates a FooView
(subclass of NSView
) on top of the MyView
, and the mouse-dragged events resize the frame of the FooView
. This might be related, as I've only been able to reproduce the problem after one of these FooView
s has been created. FooView
does not implement any of the mouse event 开发者_如何学JAVAmethods.
I've been messing with this for a while now and haven't been able to either purposely reproduce the problem or recreate the problem in a simple example. I'd be happy to answer any questions about my code, I'm just not sure what would be the relevant part to post.
Not sure what the root issue is (this Cocoa behavior seems inconsistent to me)... but here's one possible workaround:
- In the superview, create an instance variable tracking the
MyView
instance in which the-mouseDown:
occurred. - When you receive a
-mouseDragged:
inMyView
, instead of operating onself
, operate on theMyView
instance reference stored in the superview.
...then you'll be able to consistently track which object is being dragged, without having to run your own event loop.
You need to run you own mouse tracking loop in the view until mouse is up. You can extend it to process more types of events by passing them into nextEventMatchingMask:.
- (void)mouseDown:(NSEvent*)event
{
CGPoint hitPoint = [self pointInViewSpaceFromEvent:event];
BOOL isDragging = NO;
BOOL isTracking = YES;
while (isTracking)
{
switch ([event type])
{
case NSLeftMouseDown:
[self singleMouseDownAtPoint:hitPoint withModifierFlags:[event modifierFlags]];
break;
case NSLeftMouseUp:
isTracking = NO;
if (isDragging)
[self mouseDraggingDidEndAtPoint:hitPoint];
else
[self singleMouseUpAtPoint:hitPoint withEvent:event];
break;
case NSLeftMouseDragged:
if (isDragging)
[self mouseDraggingAtPoint:hitPoint withModifierFlags:[event modifierFlags]];
else
isDragging = YES;
break;
default:
break;
}
if (isTracking)
{
event = [[self window] nextEventMatchingMask:NSLeftMouseDraggedMask | NSLeftMouseUpMask];
hitPoint = [self pointInViewSpaceFromEvent:event];
}
}
}
精彩评论