NSWindow运动期间的通知

时间:2011-03-09 15:37:02

标签: objective-c nswindow

如何通过拖动标题栏来更改NSWindow的位置时收到通知? 我知道我可以使用windowWillMove:windowDidMove:通知,但只有在拖动开始或结束时,这些通知才会给我通知。

4 个答案:

答案 0 :(得分:3)

我有一个解决方案,可以让您在拖动时确定窗口的位置。

这两个问题是,在拖动窗口时没有内置的通知方式,窗口的框架不会更新,直到它停止移动。我的方法通过设置重复计时器并跟踪光标的位移来解决这些问题。

首先,订阅NSWindowWillMoveNotificationNSWindowDidMoveNotification以确定窗口何时开始和停止移动。

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(windowWillMove:)
                                             name:@"NSWindowWillMoveNotification"
                                           object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(windowDidMove:)
                                             name:@"NSWindowDidMoveNotification"
                                           object:nil];

当窗口即将移动时,记录光标的位置并启动一个重复计时器,调用你自己的"窗口被拖动"方法

- (void)windowWillMove:(NSNotification *)notification {
    if (notification.object == self.view.window) { // make sure we have the right window
        self.dragCursorStartPos = [NSEvent mouseLocation];
        const NSTimeInterval dragDelaySeconds = 0.1; // polling rate delay
        self.dragWindowTimer = [NSTimer scheduledTimerWithTimeInterval:dragDelaySeconds
                                                                target:self
                                                              selector:@selector(myMethod)
                                                              userInfo:nil
                                                               repeats:YES];
    }
}

当窗口完成移动时,请停止重复计时器。

- (void)windowDidMove:(NSNotification *)notification {
    if (notification.object == self.view.window) { // make sure we have the right window
        if (self.dragWindowTimer != NULL) {
            [self.dragWindowTimer invalidate];
            self.dragWindowTimer = NULL;
        }
    }
}

现在,聪明/ hacky部分是我们通过计算光标从其起始位置的位移并将此位移添加到帧中来确定帧的实际位置&# 39;报告的起源,自窗口开始移动以来没有变化。

- (void)myMethod {
    NSPoint cursorPos = [NSEvent mouseLocation];
    NSPoint cursorDisplacement = NSMakePoint(cursorPos.x - self.dragCursorStartPos.x, cursorPos.y - self.dragCursorStartPos.y);
    CGPoint frameOrigin = self.view.window.frame.origin;
    CGPoint actualFrameOrigin = CGPointMake(frameOrigin.x + cursorDisplacement.x, frameOrigin.y + cursorDisplacement.y);
    NSLog(@"The frame's actual origin is (%f, %f)", actualFrameOrigin.x, actualFrameOrigin.y);
}

actualFrameOrigin中的myMethod点将报告帧实际位置,即使self.view.window.frame.origin点仅在您停止拖动窗口时更新。

这种方法可以让您在拖动窗口时收到通知并告诉您它的实际位置,这样您就可以全部设置!


我发现的唯一问题是在不移动光标的情况下快速按下标题栏会触发NSWindowWillMoveNotification但不会NSWindowDidMoveNotification,这会导致计时器错误地重复。要处理这种情况,我们可以通过检查myMethod来检查(pressedButtons & (1 << 0)) == (1 << 0)中是否按下了鼠标左键。如果没有按下按钮,我们只需取消定时器。

答案 1 :(得分:0)

我绝对不是Cocoa专家,但是AFAIK windowDidMove会发出通知,即使你还在拖动时只需稍微休息一下(鼠标左键仍然按下,鼠标移动半秒左右) )。

看两件事怎么样:你知道窗口拖动开始,你知道什么时候完成。观察鼠标移动之间的时间,然后你得到移动的窗口位置。

答案 2 :(得分:0)

我建议看一下这个链接: http://www.cocoabuilder.com/archive/cocoa/31183-nswindow-not-updating-position-when-being-dragged.html

回答者说可以使用windowWillMove事件来启动一个必须调用updateWindow的计时器(这似乎是关键的东西)然后你可以定期读取框属性应该更新,然后在windowDidMove停止计时器。

答案 3 :(得分:0)

Swift 5 解决方案 ⤵︎

// Drop into `applicationDidFinishLaunching`
NotificationCenter.default.addObserver(
    self,
    selector: #selector(didChange),
    name: NSWindow.didChangeScreenNotification,
    object: nil
)

// Drop into same class
@objc func didChange() {
    print("Changed")
}