【问题标题】:Mac OS X: Convert between NSView coordinates and global screen coordinatesMac OS X:在 NSView 坐标和全局屏幕坐标之间转换
【发布时间】:2014-02-13 10:10:23
【问题描述】:

我的多显示器设置中有以下情况:

在这个例子中,我想将一个窗口精确地定位在黄色箭头所描绘的坐标处。然而,我所拥有的只是一个 NSView 的坐标,它是一个 NSWindow 的 contentView 的子视图,它跨越整个(更大的,上)辅助监视器。

以下是全局坐标空间的定义方式:

  • {0,0} 是我笔记本电脑屏幕左上角的坐标。 (绿色)
  • {-296, -1080} 是我第二个屏幕左上角的坐标(黑色)
  • {0, 800} 为左下角坐标(此处无箭头)

因此 y 从绿色箭头向下增加,从绿色箭头向上减少。

问题:

如何将黄色箭头所描绘的点({100,100},NSView inside NSWindow inside this NSScreen)转换为该全局坐标系。 (注意:在 NSView 中,坐标系的左下角有 {0,0},向上增加。)

我相信正确的答案是 {-196, -980},但是对于任何屏幕上的任何窗口进行这种转换的代码是什么?

我已经在这个问题上花费了太多时间,因此非常感谢任何帮助。

(不确定是否相关,但底部屏幕有视网膜分辨率显示。)

【问题讨论】:

    标签: macos core-graphics coordinate-systems coordinate-transformation


    【解决方案1】:

    Mac OS 在不同的地方使用不同的坐标系。视图可以定义它们是否具有向上或向下的 y 轴 (isFlipped)。窗口的原点以向上 y 轴的“屏幕坐标”表示。屏幕使用全局坐标系排列,y 指向下方。

    最好不要尝试自己做所有坐标空间的转换,而是让负责的对象来做:

    NSView *yellowView; // your view that contains the point with the yellow arrow.
    NSPoint yellowPoint = { 100, 100 };
    
    NSPoint pointInWindow = [yellowView convertPoint:yellowPoint toView:nil];
    NSPoint pointOnScreen = [[yellowView window] convertRectToScreen:(CGRect){.origin=pointInWindow}];
    
    NSWindow *newWindow = [[NSWindow alloc] initWithContentRect:(CGRect){ pointOnScreen, {32, 32}} styleMask: ...];
    

    【讨论】:

    • 我认为:NSPoint pointOnScreen = [[yellowView window] convertRectToScreen:(CGRect){.origin=pointInWindow}]; 应该是:NSPoint pointOnScreen = [[yellowView window] convertRectToScreen:(CGRect){.origin=pointInWindow}].origin;
    【解决方案2】:

    公认答案的Swift(4.0)版本基本相同:

    let yellowView: NSView // your view that contains the point with the yellow arrow.
    let yellowPoint = NSPoint(x: 100, y: 100)
    
    let pointInWindow = yellowView.convert(yellowPoint, to: nil)
    let pointOnScreen = yellowView.window?.convertToScreen(NSRect(origin: pointInWindow, size: .zero)).origin ?? .zero
    
    let contentRect = NSRect(origin: pointOnScreen, size: NSSize(width: 32, height: 32))
    let newWindow = NSWindow(contentRect: contentRect, styleMask: ...)
    

    以下是另一种方法:

    let someView: NSView // Some existing view
    var rect: NSRect
    
    rect = NSRect(x: 100, y: 100, width: 0, height: 0)
    rect = someView.convert(rect, to: nil)
    rect = someView.window?.convertToScreen(rect) ?? rect
    rect.size = NSSize(width: 32, height: 32)
    let newWindow = NSWindow(contentRect: rect, styleMask: ...)
    

    后一种方式只是提前设置矩形。对于喜欢演练的人来说,这是一个逐个播放的游戏:

    1.创建一个矩形。在视图坐标系中的所需位置初始化一个大小为零的矩形。

    let someView: NSView // Some existing view
    var rect = NSRect(x: 100, y: 100, width: 0, height: 0)
    

    2。从视图转换到窗口。 通过将目标view 指定为nil,将矩形从视图坐标系转换到窗口坐标系。

    rect = someView.convert(rect, to: nil)
    

    3.从窗口转换到屏幕。 接下来,将矩形从窗口坐标系转换到屏幕坐标系。

    请注意someView.window 可能是nil,因此我们使用可选链接(即window? 中的?)并回退到rect 的原始值(如果是这种情况)。 em> 这可能不是必需的,但这是一个好习惯。

    rect = someView.window?.convertToScreen(rect) ?? rect
    

    4.设置矩形的大小。 将矩形更新为新窗口所需的大小。

    rect.size = NSSize(width: 32, height: 32)
    

    5.创建窗口。 使用转换后的矩形初始化一个新窗口。

    let newWindow = NSWindow(contentRect: rect, styleMask: ...)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-04
      • 2016-11-11
      • 1970-01-01
      • 2011-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多