質問

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 FooViews has been created. FooView does not implement any of the mouse event methods.

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:

  1. In the superview, create an instance variable tracking the MyView instance in which the -mouseDown: occurred.
  2. When you receive a -mouseDragged: in MyView, instead of operating on self, operate on the MyView 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];
        }
    }
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top