Уведомление во время движения NSWindow - PullRequest
3 голосов
/ 09 марта 2011

Как я могу получить уведомление, когда позиция NSWindow изменяется путем перетаскивания его заголовка?Я знаю, что могу использовать уведомления windowWillMove: и windowDidMove:, но они будут давать мне уведомление только тогда, когда перетаскивание начнется или закончится.

Ответы [ 3 ]

3 голосов
/ 12 июля 2015

У меня есть решение, которое позволяет вам определять положение окна во время его перетаскивания.

Две проблемы заключаются в том, что нет встроенного способа получать уведомления во время перетаскивания окна и что рамка окна не обновляется, пока не перестанет двигаться.Мой подход обходит эти проблемы, устанавливая повторяющийся таймер и отслеживая смещение курсора.

Сначала подпишитесь на NSWindowWillMoveNotification и NSWindowDidMoveNotification, чтобы определить, когда окно запускается и останавливается.

[[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;
        }
    }
}

Теперь умная / хакерская часть заключается в том, что мы определяем фактическую позицию кадра, вычисляя смещение курсора изего начальная позиция и добавление этого смещения к указанному источнику фрейма, который не изменился с тех пор, как окно начало двигаться.

- (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).Если кнопка не удерживается, мы просто отменяем таймер.

0 голосов
/ 08 августа 2012

Я бы порекомендовал посмотреть по этой ссылке: http://www.cocoabuilder.com/archive/cocoa/31183-nswindow-not-updating-position-when-being-dragged.html

Ответчик говорит, что можно использовать событие windowWillMove, чтобы запустить таймер, который должен вызывать updateWindow (что здесь очень важно), затем вы можете периодически читать свойство frame, которое должно быть обновлено, а затем остановите таймер на windowDidMove.

0 голосов
/ 09 марта 2011

Я абсолютно не эксперт по какао, но AFAIK windowDidMove выдает уведомление, даже если вы все еще перетаскиваете и просто делаете небольшой перерыв (левая кнопка мыши все еще нажата, мышь не перемещается в течение полсекунды или около того).

Как насчет просмотра двух вещей: вы знаете, что начинается перетаскивание окна, и вы знаете, когда оно заканчивается. Время между наблюдением за движением мыши, затем вы получили положение вашего подвижного окна.

...