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