NSWindow 移动期间的通知
当通过拖动标题栏来更改 NSWindow
的位置时,如何获得通知? 我知道我可以使用 windowWillMove:
和 windowDidMove:
通知,但这些通知仅在拖动开始或完成时才会给我通知。
How can I get a notification while a NSWindow
's position is changed by dragging its titlebar?
I know I can use the windowWillMove:
and windowDidMove:
notifications, but those will give me a notification only when a drag is started or finished.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我有一个解决方案,允许您在拖动窗口时确定窗口的位置。
这两个问题是,在拖动窗口时没有内置方法可以收到通知,并且窗口的框架在停止移动之前不会更新。我的方法通过设置重复计时器并跟踪光标的位移来解决这些问题。
首先,订阅
NSWindowWillMoveNotification
和NSWindowDidMoveNotification
以确定窗口何时开始和停止移动。当窗口即将移动时,记录光标的位置并启动一个重复计时器来调用您自己的“窗口正在被拖动”方法。
当窗口完成移动后,停止重复计时器。
现在,聪明/黑客的部分是,我们通过计算光标相对于其起始位置的位移并将该位移添加到框架报告的原点(自窗口启动以来没有改变)来确定框架的实际位置移动。
myMethod
中的actualFrameOrigin
点将报告框架的实际位置,即使self.view.window.frame.origin
点仅在以下情况下更新:你停止拖动窗口。这种方法可以让您在拖动窗口时收到通知,并告诉您其实际位置,这样就一切就绪了!
我发现的唯一问题是,快速按标题栏而不移动光标将触发 NSWindowWillMoveNotification,但不会触发 NSWindowDidMoveNotification,这会导致计时器错误地持续重复。为了处理这种情况,我们可以通过检查 if
(pressedButtons & (1 << 0)) == (1 < ;<0)
。如果没有按住按钮,我们就取消计时器。I have a solution that allows you to determine the window's position while it is being dragged.
The two issues are that there's no built-in way to get notified while the window is being dragged and that the window's frame doesn't update until it stops moving. My approach works around these issues by setting up a repeating timer and keeping track of the cursor's displacement.
First, subscribe to
NSWindowWillMoveNotification
andNSWindowDidMoveNotification
to determine when the window starts and stops moving.When the window is about to move, record the position of the cursor and start a repeating timer that calls your own "window is being dragged" method.
When the window is finished moving, stop the repeating timer.
Now, the clever/hacky part is that we determine the frame's actual position by calculating the cursor's displacement from its starting position and adding this displacement to the frame's reported origin, which hasn't changed since the window started moving.
The
actualFrameOrigin
point inmyMethod
will report where the frame actually is, even though theself.view.window.frame.origin
point only updates when you stop dragging the window.This approach lets you get notified while the window is being dragged and tells you its actual position, so you're all set!
The only issue I've found is that pressing the title bar quickly without moving the cursor will fire
NSWindowWillMoveNotification
but notNSWindowDidMoveNotification
, which causes the timer to incorrectly keep repeating. To handle this case, we can check if the left mouse button is being held down inmyMethod
by checking if(pressedButtons & (1 << 0)) == (1 << 0)
. If the button is not held down, we just cancel the timer.我绝对不是 Cocoa 专家,但据我所知,即使您仍在拖动并稍事休息,
windowDidMove
也会发出通知(鼠标左键仍然按下,鼠标在半秒左右没有移动) )。观察两件事怎么样:您知道窗口拖动开始,并且您知道它何时完成。观察鼠标移动之间的时间,然后你就得到了移动窗口位置。
I'm absolutely no Cocoa expert, but AFAIK
windowDidMove
gives a notification even when you are still dragging and just take a little break (left mouse button still pressed, mouse is not moved for half a second or so).What about watching two things: You know that the window drag starts and you know when it is finished. The time between watch the mouse movement, then you got your moving window position.
我建议查看此链接:
http://www.cocoabuilder .com/archive/cocoa/31183-nswindow-not-updating-position-when-being-dragged.html
回答者说可以使用
windowWillMove
事件来启动计时器必须调用 updateWindow (这似乎是这里的关键),然后您可以定期读取应该更新的框架属性,然后在 windowDidMove 处停止计时器。I would recommend looking at this link:
http://www.cocoabuilder.com/archive/cocoa/31183-nswindow-not-updating-position-when-being-dragged.html
The answerer is saying that one can use the
windowWillMove
event to start a timer that has to callupdateWindow
(which seems to be the critical thing here) then you can periodically read the frame property which should be updated, and then stop your timer atwindowDidMove
.Swift 5解决方案⤵︎
Swift 5 solution ⤵︎
对我来说,依靠
windowDidUpdate
就足够了,并且没有像其他建议的解决方案那样设置计时器。所以在我的自定义窗口委托中我只是这样做了:For me relying on
windowDidUpdate
was enough and no timer was set up as for the other proposed solutions. So in my custom window delegate I just did this: