【问题标题】:How to find if the mouse is over a view如何查找鼠标是否在视图上
【发布时间】:2011-01-07 21:32:59
【问题描述】:

我需要确定鼠标位置是否在 NSView 的矩形内。

我会使用NSPointInRect(point, rect),但我需要将矩形坐标转换为屏幕坐标,但我不确定如何。任何帮助将不胜感激!

【问题讨论】:

  • 你能给我们一个理由吗?一般来说,这种技术不是一个好主意,但如果不知道你在写什么,就很难说。

标签: objective-c cocoa macos nsview


【解决方案1】:

这样的东西应该适合你:

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
}

我个人没有使用这么多局部变量,但希望这能让这个例子更清晰。

【讨论】:

  • NSEvent 已经有一个 [event locationInWindow] 所以前 3 行是多余的
  • locationInWindow 可能大部分时间都可以工作。但这是来自 Apple 文档:“使用 NSMouseMoved 和可能的其他事件,接收器可以有一个 nil 窗口(即,窗口返回 nil)。在这种情况下,locationInWindow 返回屏幕坐标中的事件位置。”所以看起来不依赖 locationInWindow 可能更健壮。如果您已经有一个事件,那么 locationInWindow 肯定是要使用的调用。即使您还没有事件对象,我的答案中的方法也可以工作。
【解决方案2】:

使用 NSView 的 convertPoint:fromView: 方法和 fromView 作为 nil 将窗口坐标中的点转换为视图的坐标系。

将鼠标点转换为视图坐标系后,我将使用 NSView 的 mouse:inRect: 方法而不是 NSPointInRect,因为前者也考虑了翻转坐标系。

或者,您可以使用Tracking Area Object

【讨论】:

  • NSTrackingArea 正是我想要的!谢谢!
  • 我正在绑定这个...但是 convertPoint 函数实际上要求一个 NSPoint 对象作为它的第一个参数。我应该给什么。请详细说明。
  • 我想补充一点,您应该将self.bounds 传递给NSView's mouse:inRect: 中的NSRect 参数,向上发送self.frame 将抵消坐标。
【解决方案3】:

NSView isMousePoint 功能对我有用,无需担心任何 CG。

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

【讨论】:

    【解决方案4】:

    一些使用 mouse:inRect: 的代码:(推荐的方式;考虑翻转坐标)

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

    【讨论】:

      【解决方案5】:

      这些答案都没有考虑到视图可能不是矩形的。

      这是一种适用于非矩形视图的通用方法。想想表盘或复杂的路径形状。

      此代码 sn-p 将为您提供来自 globalPoint(又名 globalToLocal)的 localPoint。 (0,0 窗口空间中的 GlobalPoint)如果您将参数更改为“toView”,那么您将获得一个“localToGlobal”点。

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

      如果该点是否在路径内,下面的代码将返回 true 或 false。

      CGPathContainsPoint(someCGPath,nil,localPoint,true)

      注意: aPoint是从hitTest中的参数导出的globalPoint,也可以从:

      (self.window?.mouseLocationOutsideOfEventStream)!
      

      注意: 可能有更正确的方法来做到这一点。但这有效,并且不关心翻转视图。

      【讨论】:

      • 即使采用上述方法仍然存在缺陷。例如,我很难找到一个干净的解决方案来在 NSView 的层次结构中对 TextField 进行 hitTesting。由于苹果在 hitTesting textField 方面改变了他们的策略,因此您也必须采用。我找到了一种方法来让它工作并且相当干净。然而,我可能会开始翻转和偏移层次结构中每个视图中的每个 hitTestPoint,因为这似乎是苹果对其组件所做的事情。只需将其添加到我使用的每个 View 类中包含的方法中即可。
      • 这是一篇非常“杂乱无章”的文章,但它可能会让您了解哪些不该尝试。 stylekit.org/blog/2016/01/28/Hit-testing-sub-views(它基本上是我从 hitTesting 研究中得到的所有笔记)我已经继续前进,并且在 hitTesting 方面有一个干净的工作流程。
      猜你喜欢
      • 1970-01-01
      • 2011-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-08
      • 2016-03-26
      • 1970-01-01
      相关资源
      最近更新 更多