13

我在多顯示器設置以下情況:的Mac OS X:一個NSView座標和全局畫面之間的轉換座標

OSX coordinate conversions

在這個例子中,我要定位一個窗口正好位於座標描述與黃色箭頭。但是,我所做的全部都是NSView的座標,它是NSWindow的contentView的子視圖,跨越整個(較大,較高)輔助監視器。

這裏的全局座標空間是如何定義的:

  • {0,0}是我的筆記本電腦屏幕的左上角的座標。 (綠色)
  • {-296,-1080}是我的第二個屏幕的左上角(黑色)
  • {0,} 800的座標是左下角的(這裏沒有箭頭)座標

因此y從綠色箭頭向下增加,從綠色箭頭向上減小。

問題:

如何轉換由黃色箭頭所示的點({} 100,100,裏面的NSView這NSWindow裏面NSScreen)轉換爲全局座標系。 (注意:在一個NSView的座標系統在左下角{0,0},向上增加。)

我認爲正確的答案是{-196,-980},但最新的代碼在任何屏幕上的任何窗口獲得此轉換?

我已經在這個問題上花了太多時間了,所以任何幫助都非常感謝。

(不知道是否有關,但屏幕下方有一個視網膜分辨率顯示。)

回答

20

的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: ...]; 
+0

親愛的尼古拉,請您提供一個Swift解決方案。我無法翻譯你的答案。 – ixany

+1

@ixany我在下面添加了一個Swift等價物。 –

1

雨燕(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原來的值,如果是這樣的話。這可能沒有必要,但這是一個很好的習慣。

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

4.設置矩形的大小。更新所需大小的新窗口的矩形。

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

5.創建窗口。用轉換後的矩形初始化一個新窗口。

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