2014-03-13 56 views
2

假設我有一個浮動的無邊界圓形NSWindow根據點擊位置放棄NSWindow上的鼠標事件

它是循環的,因爲內容視圖只是繪製一個紅色圓圈。

該內容視圖需要分層支持([contentView setWantsLayer:YES]),因爲我正在對其應用CoreAnimations,例如動畫縮放。

通常,NSWindow的可點擊區域由內容視圖像素的透明度來定義。但是,一旦NSWindow的內容視圖變成了分層支持,不幸的是,透明區域也會收到點擊。

在我的情況下,這是一個嚴重的問題,因爲我只想在半徑內接收點擊。但是現在,在窗口矩形內單擊,但超出圓弧半徑,將激活窗口(從而激活整個應用程序),但不應該這樣做。此外,該窗口可通過其內容視圖的角落拖動。

click location

我最初的想法是實現在子類中[NSWindow sendEvent:]並查看點擊是否半徑內執行,使用[theEvent locationInWindow]。我想我可以簡單地放棄這個事件,如果它超出了半徑範圍,那麼不要致電[super sendEvent:theEvent]。然而這並沒有奏效:我注意到,mouseDown:;窗口方法甚至在sendEvent之前被調用:;方法。

我搜索了很多,但我發現的唯一想法是在窗口頂部有一個非層支持NSWindow的代理,它有條件地委託點擊,但這導致了不可預測的UI行爲。

你們有什麼想法,如何解決它?

+0

您是否嘗試過在應用程序級別通過繼承'NSApplication'並實現'-sendEvent:'重寫來攔截事件? – indragie

+0

我剛剛測試過,沒有成功。即使我試圖通過從不調用NSApplication子類中的''super sendEvent:'''拋棄任何**事件,窗口一直通過拖動鼠標來移動。另外,覆蓋'''[NSApplication postEvent:]'''不起作用。 – Raffael

回答

1

所以在幾個星期後,我來到了以下結果:

A)代理窗口: 製作使用非層支持的代理窗口,它被放置在目標窗口的頂部一個孩子的窗戶。代理窗口具有與目標窗口相同的形狀,並且由於它不是層次支持的,它將正確接收和忽略事件。代理窗口通過覆蓋sendEvent:將所有事件委託給目標窗口。目標窗口被設置爲忽略所有的鼠標事件。

B)全球鼠標指針觀察: 使用addGlobalMonitorForEventsMatchingMaskaddLocalMonitorForEventsMatchingMaskNSMouseMovedMask|NSLeftMouseDraggedMask事件同時安裝全局和局部事件監視器。事件監視器根據當前全局鼠標位置禁用並啓用忽略所有已註冊目標窗口上的鼠標事件。在圓形窗口的情況下,必須計算鼠標指針和每個目標窗口之間的距離。

這兩種方法在一般情況下都能正常工作,但是我一直在經歷子窗口方法的某些不可預知的錯誤行爲(其中子窗口與其父位置「不同步」)。

UPDATE:兩種方法都有一些缺點顯著: 在A)中,代理窗口有時可能不同步的並且可以被關閉的實際窗口略微放置。

在B)中,即使應用程序不是最前面的應用程序,事件監視器在移動鼠標時對電池壽命有很大影響。

+0

請檢查http://stackoverflow.com/questions/29441015/click-through-custom-nswindow –

1

如果你想基於位置可以使用到廢棄mouseDown事件:

CGPathContainsPoint(path,transform,point,eoFill):Bool 

安裝路徑,以匹配您的圖形。圓形,橢圓形,矩形,三角形或路徑,甚至組成路徑(其中有孔的路徑)。

+0

然後呢?在這種情況下,hitTest()可以被覆蓋返回nil,但似乎不會將點擊發送到下一個窗口。 –

+0

重寫hitTest方法並處理hitTest方法內的代碼。然後,如果mouseDown點位於路徑之外,則將hitTest事件轉發給super。 – eonist

+0

基本上:返回零,停止事件流。超級轉發事件繼續傳播事件。 – eonist