1

I wanted to change the cursor in my cocoa application. I've followed the example in this answer, with success.

I have an NSView, let's call it NSViewA, behind another NSView, NSViewB. NSViewA contains a subclassed NSButton where the cursor has been changed. NSViewA and NSViewB have the same superview. So something like this:

- NSWindow
    - NSViewA
        - NSButtonSubclass
    - NSViewB

My problem is that when NSViewB is shown, and the cursor is ontop of NSViewB, but in the same x y coordinates of the NSButton behind NSViewB, the cursor changes to that specified in the NSButton subclass.

How do I stop this behaviour?

The reason for this layout is that I'm creating a 'lightbox' control. If you think something along the lines of the NSWindow greying out, and a centred box appearing showing an error message. That sort of thing.

I previously had a problem where you could still click buttons, etc, behind NSViewB. This was solved by suppressing mouseDown: and mouseUp:. I've tried doing something similar with other mouse-related events, such as mouseEntered: and mouseExited: with no luck.

Community
  • 1
  • 1
DJH
  • 2,191
  • 4
  • 28
  • 45
  • So NSViewB does not entirely cover NSViewA? – mangerlahn Apr 01 '16 at 15:48
  • @Max `NSViewB` is the same size and is in front of `NSViewA`, and they both fill the `NSWindow`. `NSViewB` is only visible when I need to show a message. When it's visible, it does cover all of `NSViewA`. `NSViewB` is the semi-transparent dark overlay covering the `NSWindow`, which contains a child `NSView` which is my custom message box. `NSViewA` is the 'root' view containing all the UI for my app. – DJH Apr 01 '16 at 16:01
  • Therefore you can't just hide NSViewA? – mangerlahn Apr 01 '16 at 16:23
  • @Max correct. Although `NSViewB` does cover all of `NSViewA`, parts of `NSViewA` can still be seen through the semi-transparent section of `NSViewB`, albeit they appear faded due to the overlay. It's only `NSViewB`'s child `NSView` (smaller and centred) which visually hides the content from `NSViewA`. – DJH Apr 01 '16 at 16:35
  • After posting my answer I began to wonder why you couldn't just use a new temporary``NSWindow`` to do the job of ``viewB``. This is a much more Cocoa-like solution in that sheets and modal alert dialogs are windows, and your ``viewB`` is doing much the same job as they do in native apps. Plus you don't have to change the behaviour of ``viewA`` in any way. – Paul Patterson Apr 02 '16 at 19:31

1 Answers1

1

Could you make the addition of your custom cursor rectangle contingent on the enabled status of your button? In other words, your resetCursorRects would look like this:

// MyButton.swift
override func resetCursorRects() {
    if enabled {
        addCursorRect(bounds, cursor: NSCursor.pointingHandCursor())
    }
}

Whenever viewB is about to be shown, disable the button, and call for the rects belonging to your button to be invalidated. If you're using Swift, you could do this second bit in a property observer attached to the enabled property itself:

// MyButton.swift
override var enabled: Bool {
    didSet {
        window!.invalidateCursorRectsForView(self)
    }
}

If you don't want your button to take on a disabled look, make the addCursorRect call contingent on some other flag.

Paul Patterson
  • 6,840
  • 3
  • 42
  • 56
  • Thanks for the suggestion. My example above is simplified, as in reality I have quite a few places where the cursor has changed, in various subviews of `NSViewA`, and not just on some `NSButton`s. I'm hoping this can work with something like [this](http://stackoverflow.com/a/11740823/1229237). I'm going to give it a try a little later. I'm still quite new to cocoa, with mainly a .NET background. – DJH Apr 01 '16 at 17:08