开发者

How to find if the mouse is over a view

开发者 https://www.devze.com 2023-02-03 16:20 出处:网络
I need to find if the mouse position is inside an NSView\'s rect. I\'d use NSPointInRect(point, rect), but I\'d need to convert the rect coordinates to screen coordinates and I\'m not sure how. Any开

I need to find if the mouse position is inside an NSView's rect.

I'd use NSPointInRect(point, rect), but I'd need to convert the rect coordinates to screen coordinates and I'm not sure how. Any开发者_Go百科 help would be much appreciated!


Something like this should work for you:

NSView* myView; // The view you are converting coordinates to
NSPoint globalLocation = [ NSEvent mouseLocation ];
NSPoint windowLocation = [ [ myView window ] convertScreenToBase: globalLocation ];
NSPoint viewLocation = [ myView convertPoint: windowLocation fromView: nil ];
if( NSPointInRect( viewLocation, [ myView bounds ] ) ) {
    // Do your thing here
}

I don't personally use this many local variables but hopefully this make this example clearer.


Use NSView's convertPoint:fromView: method with fromView as nil to covert a point in window coordinates to a view's coordinate system.

After converting the mouse point to the view's coordinate system, I would use NSView's mouse:inRect: method instead of NSPointInRect as the former also accounts for flipped coordinate systems.

Alternatively, you could use a Tracking Area Object.


The NSView isMousePoint function works for me, without having to worry about anything CG.

func isMouseInView(view: NSView) -> Bool? {
    if let window = view.window {
        return view.isMousePoint(window.mouseLocationOutsideOfEventStream, in: view.frame)
    }
    return nil
}


Some code making use of mouse:inRect: (the recommended way; that accounts for flipped coordinates)

CGPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
CGRect rect = [self bounds];
if ([self mouse:point inRect:rect]) {
}


None of these answers take into account that a view might not be rectangular.

Here is an universal method that works on non-rectangular views as well. Think watch-face or a complex path shape.

This code snippet will give you a localPoint from a globalPoint (aka globalToLocal). (GlobalPoint in 0,0 window space) If you change the argument to "toView" then you get a "localToGlobal" point.

let localPoint = convertPoint(aPoint, fromView: self.window?.contentView)    

The bellow code would return true or false if the point was inside the path or not.

CGPathContainsPoint(someCGPath,nil,localPoint,true)

NOTE: aPoint is a globalPoint derived from the parameter in hitTest, it can also be derived from:

(self.window?.mouseLocationOutsideOfEventStream)!

NOTE: There might be a more correct way of doing this. But this works,and doesn't care about flipped views.


It seems like many answers don't consider isFlipped flag. Here is a way that takes the view's isFlipped into account:

public extension NSView {

  /// Checks if the mouse cursor is in self, without an event.
  func containsMouseCursor() -> Bool {
    guard let window, let windowContentView = window.contentView else {
      return false
    }

    var mouseLocationInWindowContentView = window.mouseLocationOutsideOfEventStream // returns a coordinate in bottom-left origin coordinate system
    if windowContentView.isFlipped {
      // correct the coordinates if `contentView` is flipped
      mouseLocationInWindowContentView = CGPoint(mouseLocationInWindowContentView.x, windowContentView.frame.height - mouseLocationInWindowContentView.y)
    }
    // convert the cursor point into self's coordinate system
    let pointInSelf = windowContentView.convert(mouseLocationInWindowContentView, to: self)

    return isMousePoint(pointInSelf, in: bounds)
  }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消