Получение [NSEvent mouseLocation] в системе координат представления

У меня есть NSView, который ловит событие mouseDown.

Я получаю координацию щелчка мышью, используя:

- (void)mouseDown:(NSEvent *)theEvent {
    NSPoint touchPoint = [NSEvent mouseLocation];
    //Rest of code
}

Тем не менее, это устанавливает clickPoint в качестве расположения мыши в глобальной координации экрана.

Я хочу получить позицию щелчка в относительной координации вида. Если пользователь щелкает в левом нижнем углу окна, я хочу, чтобы точка была (0, 0), независимо от того, где находится окно на экране.

3 ответа

Решение

Вы должны использовать locationInWindowне mouseLocation, Документы на locationInWindow покажите как идти оттуда:

NSPoint event_location = [theEvent locationInWindow];
NSPoint local_point = [self convertPoint:event_location fromView:nil];

Swift

override func mouseMoved(with event: NSEvent) {
    let mouseLocation = event.locationInWindow
    print(mouseLocation)
}

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

      public extension NSEvent {

  /// Get the event mouse location in `view`.
  func location(in view: NSView) -> CGPoint {
    if let eventWindow = window, let viewWindow = view.window {
      if eventWindow.windowNumber == viewWindow.windowNumber {
        // same window, just convert
        return view.convert(locationInWindow, from: nil)
      } else {
        // window not equal, check screen
        if let eventScreen = eventWindow.screen, let viewScreen = viewWindow.screen {
          if eventScreen.isEqual(to: viewScreen) {
            // same screen, try to convert between windows
            // screen coordinate zero point is at bottom left corner
            let eventLocationInScreen = locationInWindow.translate(dx: eventWindow.frame.x, dy: eventWindow.frame.y)
            let viewFrameInScreen = view.frameInWindow.translate(dx: viewWindow.frame.x, dy: viewWindow.frame.y)
            return eventLocationInScreen.translate(dx: -viewFrameInScreen.x, dy: -viewFrameInScreen.y)
          } else {
            // different screen, try to convert to unified coordinate
            let eventLocationInScreen = locationInWindow.translate(dx: eventWindow.frame.x, dy: eventWindow.frame.y)
            let eventLocationInBase = eventLocationInScreen.translate(dx: eventScreen.frame.x, dy: eventScreen.frame.y)

            let viewFrameInScreen = view.frameInWindow.translate(dx: viewWindow.frame.x, dy: viewWindow.frame.y)
            let viewFrameInBase = viewFrameInScreen.translate(dx: viewScreen.frame.x, dy: viewScreen.frame.y)
            return eventLocationInBase.translate(dx: -viewFrameInBase.x, dy: -viewFrameInBase.y)
          }
        }
      }
    }

    // other unexpected cases, fall back to use `convert(_:from:)`
    return view.convert(locationInWindow, from: nil)
  }
}

public extension NSView {

  /// The view's frame in its window.
  var frameInWindow: CGRect {
    convert(bounds, to: nil)
  }
}

public extension CGRect {

  /// Move/translate a `CGRect` by its origin..
  /// - Parameters:
  ///   - dx: The delta x.
  ///   - dy: The delta y.
  /// - Returns: A new `CGRect` with moved origin.
  func translate(dx: CGFloat = 0, dy: CGFloat = 0) -> CGRect {
    CGRect(origin: origin.translate(dx: dx, dy: dy), size: size)
  }
}

Как видите, он проверяет, совпадает ли и событие, и окно просмотра, если нет, логика пытается сравнить экран и попытаться выполнить преобразование вручную.

Другие вопросы по тегам