How to find if the mouse is over a view
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)
}
}
精彩评论