Как принять щелчок мыши для одной части и разрешить щелчок по остальной части NSWindow

У меня есть приведенный ниже код для подкласса NSWindow, есть анимированное представление, которое можно масштабировать, и я хочу принять щелчок, когда он щелкнут в нужном месте, и отклонить (щелкнуть), если он снаружи.

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

- (void)mouseDragged:(NSEvent *)theEvent {
  if (allowDrag) {
    NSRect screenVisibleFrame = [[NSScreen mainScreen] visibleFrame];
    NSRect windowFrame = [self frame];
    NSPoint newOrigin = windowFrame.origin;

    // Get the mouse location in window coordinates.
    NSPoint currentLocation = [theEvent locationInWindow];
    // Update the origin with the difference between the new mouse location and the old mouse location.
    newOrigin.x += (currentLocation.x - initialMouseLocation.x);
    newOrigin.y += (currentLocation.y - initialMouseLocation.y);

    if ((newOrigin.y + windowFrame.size.height) > (screenVisibleFrame.origin.y + screenVisibleFrame.size.height)) {
        newOrigin.y = screenVisibleFrame.origin.y + (screenVisibleFrame.size.height - windowFrame.size.height);
    }

    // Move the window to the new location
    [self setFrameOrigin:newOrigin];
  }
}



- (void)mouseDown:(NSEvent *)theEvent
{
    screenResolution = [[NSScreen mainScreen] frame];

   initialMouseLocation = [theEvent locationInWindow];

    float scale = [[NSUserDefaults standardUserDefaults] floatForKey:@"widgetScale"]/100;

    float pX = initialMouseLocation.x;
    float pY = initialMouseLocation.y;
    float fX = self.frame.size.width;
    float fY = self.frame.size.height;

    if (pX>(fX-fX*scale)/2 && pX<(fX+fX*scale)/2 && pY>(fY+fY*scale)/2) {
        allowDrag = YES;
    } else {
        allowDrag = NO;
    }
}

person Tibidabo    schedule 03.03.2013    source источник


Ответы (2)


В Cocoa у вас есть два основных варианта: 1) вы можете сделать так, чтобы клики проходили через все окно с помощью [window setIgnoresMouseEvents:YES], или 2) вы можете сделать части окна прозрачными, и клики будут проходить по умолчанию.

Ограничение состоит в том, что оконный сервер принимает решение о том, какому приложению доставить событие один раз. После того, как оно доставило событие в ваше приложение, невозможно заставить его вернуть событие и доставить его в другое приложение.

Одним из возможных решений может быть использование Quartz Event Taps. . Идея состоит в том, что вы заставляете свое окно игнорировать события мыши, но настраиваете касание события, которое будет видеть все события сеанса входа в систему. Если вы хотите, чтобы событие, проходящее через ваше окно, фактически останавливалось в вашем окне, вы обрабатываете его вручную, а затем отбрасываете. Вы не позволяете событию продолжаться в приложении, которое в противном случае было бы достигнуто. Я ожидаю, что это будет очень сложно сделать правильно. Например, вы не хотите перехватывать события для окна другого приложения, которое находится перед вашим.

Если возможно, я рекомендую вам использовать методы, поддерживаемые Cocoa. Я думаю, вы бы хотели, чтобы клики проходили только через ваше окно, где оно прозрачно, иначе как пользователь узнает, на что он нажимает?

person Ken Thomases    schedule 03.03.2013
comment
К сожалению, ничего не работает, как я ожидал. Когда я масштабирую вид окна с помощью базовой анимации, он делает много прозрачной части, но эти части по-прежнему принимают щелчки мыши, потому что исходная прозрачность имеет значение, а не слой анимации. Он также должен быть дружественным к App Store, поэтому ловушки событий не годятся. Я уже отправил приложение как есть, с ошибкой, если я получаю много жалоб, вероятно, лучше всего, если я просто изменю размер окружающего окна до того же размера, что и масштабированное представление. В любом случае, спасибо. - person Tibidabo; 09.03.2013
comment
Я не знаю, как во время анимации, но определенно после завершения анимированного изменения размера попробуйте вызвать -[NSWindow invalidateShadow]. Это должно убедиться, что оконный сервер обновляет свое представление о форме окна. - person Ken Thomases; 09.03.2013

Пожалуйста, вызовите прозрачное наложение CHILD WINDOW для принятия управления и сделайте главное окно -setIgnoresMouseEvents:YES, как указал Кен.

Я использовал этот трюк в своем приложении под названием «Наложение».

person Jiulong Zhao    schedule 23.10.2013