Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing NSCursor for NSView above an NSTextView

Tags:

macos

swift

cocoa

Found a similar question to mine(this), but my issues seems to be a bit more associated with view hierarchy.

I have a NSTextView, then as sibling views, several other NSViews on top of it.

Similar to the question linked above, I setup a tracking area, and applied the cursor as such:

class CursorChangingView: NSView {
    override func updateTrackingAreas() {
        let trackingArea = NSTrackingArea(rect: 
    }

    override func cursorUpdate(event: NSEvent) {
        NSCursor.arrowCursor().set()
    }
}

It does seem to work when hovering, but immediately goes back to the IBeam Cursor, which is the default cursor for NSTextViews under this CursorChangingView.

Is this the proper way of applying changing the cursor when hovering over a certain NSView, and is the NSTextView under it overriding my overrriding?

like image 665
Naoto Ida Avatar asked Sep 08 '15 00:09

Naoto Ida


2 Answers

All you need is to subclass a custom view, override awakeFromNib method, add the custom tracking area for [.mouseMoved, .activeAlways] events: NSTrackingArea Info there. There is no need to override resetCursorRects and/or updateTrackingAreas. All you need is to override mouseMoved method and set the desired cursor there:

Note about discardCursorRects method:

From the docs

You need never invoke this method directly

Xcode 9 • Swift 4

import Cocoa

class CursorChangingView: NSView {

    override func awakeFromNib() {

        addTrackingArea(NSTrackingArea(rect: bounds, options: [.activeAlways, .mouseMoved], owner: self, userInfo: nil))

        wantsLayer = true
        layer?.backgroundColor = NSColor.cyan.cgColor
        layer?.borderColor = NSColor.black.cgColor
        layer?.borderWidth = 1
    }

    @objc override func mouseMoved(with theEvent: NSEvent) {
        NSCursor.pointingHand.set()
    }
}

Sample

like image 117
Leo Dabus Avatar answered Oct 13 '22 05:10

Leo Dabus


Thanks @Leo Dabus for your answer, but I managed to solve it, so I will post my answer too.

In my case, for some reason, mouseEntered and mouseEntered did not work at all.

So here is my code that finally got it to work:

class CursorChangingView: NSView {
    let trackingArea: NSTrackingArea?
    func setupTracking() {
        if self.trackingArea == nil {
            self.trackingArea = NSTrackingArea(rect: self.bounds, options: NSTrackingAreaOptions.ActiveAlways | NSTrackingAreaOptions.MouseMoved | NSTrackingAreaOptions.CursorUpdate | NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveInActiveApp, owner: self, userInfo: nil)
            self.addTrackingArea(self.trackingArea!)
        }
    }

    override func updateTrackingAreas() {
        self.trackingArea = NSTrackingArea(rect: self.bounds, options: NSTrackingAreaOptions.ActiveAlways | NSTrackingAreaOptions.CursorUpdate | NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveInActiveApp, owner: self, userInfo: nil)
        self.addTrackingArea(self.trackingArea!)
    }

    override func resetCursorRects() {
        self.discardCursorRects()
        self.addCursorRect(self.bounds, cursor: NSCursor.arrowCursor())
    }

    override func mouseMoved(theEvent: NSEvent) {
        NSCursor.arrowCursor().set()
    }
}

It might be a little excessive, but worked, so will share this as my own solution.

like image 30
Naoto Ida Avatar answered Oct 13 '22 05:10

Naoto Ida