15

Why can't I get the cursor to stay put for the duration of my mouse drag? As soon as I start dragging, it reverts to "Arrow" (even though I set it as open hand in the app delegate after launch).

- (void)mouseDown:(NSEvent *)event
{
   [[NSCursor closedHandCursor] push];
}

- (void)mouseUp:(NSEvent *)event
{
   [NSCursor pop];
}
borrrden
  • 33,256
  • 8
  • 74
  • 109

3 Answers3

23

If you don't want other views to change your cursor while dragging you can do in -mouseDown:

[[self window] disableCursorRects];

and in -mouseUp:

[[self window] enableCursorRects];
[[self window] resetCursorRects];
Yoav
  • 5,962
  • 5
  • 39
  • 61
  • 3
    if you go for this, make sure that mouseUp gets triggered for real. In NSTableView and other types of views as well, if you call base in mouseDown, then mouseUp doesn't get triggered anymore, because the underlying mechanism steals and "consumes" the event. Using this in mouse entered/exited might be a good solution as well – Radu Simionescu Jan 19 '16 at 10:37
12

Try using the addCursorRect:cursor: to set the cursor for you view.

Override the resetCursorRects for your view:

- (void)resetCursorRects
{
    [super resetCursorRects];
    if(drag) {
        [self addCursorRect:self.bounds cursor:[NSCursor closedHandCursor]];
    }
}

You need to call invalidateCursorRectsForView: to force update your cursor rects:

[self.window invalidateCursorRectsForView:self];

But if you want to have different cursor outside of you view you can call [[NSCursor closedHandCursor] set] in your mouseDragged: method.

Dmitry
  • 7,300
  • 6
  • 32
  • 55
  • Oh! I saw something like this but it seemed silly to override *reset* for something that I wanted to *add*. I understand now that the cursor rect gets invalidated when I change the position of the view now though! Thanks. – borrrden Jul 02 '12 at 08:15
  • 2
    The argument to addCursorRect is `[self bounds]`, not `[self frame]`. – alecail Sep 15 '12 at 15:21
1

I had the same problem which was caused by the fact that during the drag I was modifying a subview's frame, which seems to reset the cursor. When adding the tracking area with the .cursorUpdate option and resetting the cursor inside cursorUpdate(with:), it seems to work correctly.

class MyViewController: NSViewController {

    var cursor: NSCursor?

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addTrackingArea(NSTrackingArea(rect: .zero, options: [.activeInKeyWindow, .inVisibleRect, .cursorUpdate], owner: self))
    }

    override func mouseDown(with event: NSEvent) {
        cursor = NSCursor.closedHand
    }

    override func cursorUpdate(with event: NSEvent) {
        cursor?.set()
    }
        
    override func mouseUp(with event: NSEvent) {
        cursor = nil
    }
    
}
Nickkk
  • 2,261
  • 1
  • 25
  • 34