scr*_*rrr 17 macos core-graphics coordinate-systems coordinate-transformation
我的多显示器设置中存在以下情况:

在这个例子中,我想将窗口精确定位在用黄色箭头描绘的坐标处.然而,我所拥有的是NSView的坐标,它是NSWindow的contentView的子视图,跨越整个(较大的,较高的)辅助监视器.
以下是定义全局坐标空间的方式:
因此,y从绿色箭头向下增加,从绿色箭头向上减少.
问题:
如何将黄色箭头({100,100},NSScreen内的NSWindow内部的NSView)描绘的点转换为该全局坐标系.(注意:在NSView中,坐标系左下角有{0,0},向上增加.)
我相信正确的答案是{-196,-980},但是在任何屏幕上为任何窗口获取此转换的代码是什么?
我已经在这个问题上花了太多时间,所以非常感谢任何帮助.
(不确定是否相关,但底部屏幕有视网膜分辨率显示.)
Nik*_*uhe 28
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: ...];
Run Code Online (Sandbox Code Playgroud)
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: ...)
Run Code Online (Sandbox Code Playgroud)
以下是另一种方法:
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: ...)
Run Code Online (Sandbox Code Playgroud)
后一种方式只是提前设置矩形。对于那些喜欢演练的人来说,这是一个逐个播放:
1. 创建一个矩形。在视图坐标系内的所需位置初始化一个零大小的矩形。
let someView: NSView // Some existing view
var rect = NSRect(x: 100, y: 100, width: 0, height: 0)
Run Code Online (Sandbox Code Playgroud)
2. 从视图转换为窗口。通过指定nil目标,将矩形从视图的坐标系转换为窗口的坐标系view。
rect = someView.convert(rect, to: nil)
Run Code Online (Sandbox Code Playgroud)
3.从窗口转换到屏幕。接下来,将矩形从窗口坐标系转换为屏幕坐标系。
请注意,someView.window可能是nil,因此我们使用可选链接(即?in window?)并回退到原始值,rect如果是这种情况。这可能不是必需的,但这是一个很好的习惯。
rect = someView.window?.convertToScreen(rect) ?? rect
Run Code Online (Sandbox Code Playgroud)
4. 设置矩形的大小。使用新窗口的所需大小更新矩形。
rect.size = NSSize(width: 32, height: 32)
Run Code Online (Sandbox Code Playgroud)
5. 创建窗口。用转换后的矩形初始化一个新窗口。
let newWindow = NSWindow(contentRect: rect, styleMask: ...)
Run Code Online (Sandbox Code Playgroud)