Cocoa AppKit - закрытие модального окна (т. Е. Всплывающего или контекстного меню) и нажатие кнопки, находящейся в данный момент над - PullRequest
1 голос
/ 22 марта 2010

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

Загвоздка в том, что если я открываю всплывающее меню для кнопки, пользователь должен нажать еще раз, чтобы закрыть ее. Весь цикл запуска приостановлен, так как я считаю, что всплывающее меню является модальным. Как я могу отправлять [somePopUpMenu cancelTracking], когда пользователь переходит к следующей кнопке?

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

Предполагая, что всплывающее меню открыто и мышь существует, события leftdown / leftup запускаются (я знаю, что это работает, когда я регистрирую их в NSLog для mouseDown и mouseUp), таймер становится недействительным, но всплывающее меню по-прежнему показ, а другая кнопка, «нажата» поддельными событиями, ничего не показывает. Кроме того, все это зацикливается, и по какой-то причине отправляется неистовый mouseDown / mouseUp.

Стоит отметить, что всплывающее меню создано в другом объекте, хотя hookToMenu имеет правильную ссылку на него (я подтвердил отладку / пошаговое выполнение).

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

Буду признателен за любую помощь в этом.

-(void)stopTimer
{
    [timer invalidate];
    [hookToMenu cancelTracking]; //hookToMenu is NSMenu*
}

-startFireDateTimer
{
    NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:0];
    timer = [[NSTimer alloc] initWithFireDate:nil interval:0 target:self selector:@selector(targetMethod)      userInfo:nil  repeats:YES];

    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    [runLoop addTimer:timer forMode:NSEventTrackingRunLoopMode];
    [timer release];
}

-(void)targetMethod
{
    NSEvent *newEvent;

    newEvent=[NSApp nextEventMatchingMask:NSMouseExitedMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:NO];

    if ([newEvent type]==NSMouseExited)
    {
        NSPoint mouseLoc;

        mouseLoc=[newEvent locationInWindow];

        int type=NSLeftMouseDown;
        int type2=NSLeftMouseUp;
        int windowNumber=[self windowNumber];

        id fakeMouseUpEvent=[NSEvent mouseEventWithType:type
                                               location:mouseLoc
                                          modifierFlags:nil 
                                              timestamp:[NSDate timeIntervalSinceReferenceDate]
                                           windowNumber:windowNumber 
                                                context:nil
                                            eventNumber:nil 
                                             clickCount:1 
                                               pressure:1];

        id fakeMouseUpEvent2=[NSEvent mouseEventWithType:type2
                                                location:mouseLoc
                                           modifierFlags:nil 
                                               timestamp:[NSDate timeIntervalSinceReferenceDate]
                                            windowNumber:windowNumber 
                                                 context:nil
                                             eventNumber:nil 
                                              clickCount:1 
                                                pressure:1];

        [NSApp sendEvent:fakeMouseUpEvent];
        [NSApp sendEvent:fakeMouseUpEvent2];

        [self stopTimer];
    }
}

-(void)mouseDown:(NSEvent *)theEvent
{    
    [self startFireDateTimer];

    NSLog(@"WINDOW: mouse down in window!");

    [super mouseDown:theEvent];
}

-(void)mouseUp:(NSEvent *)theEvent
{    
    NSLog(@"WINDOW: mouse up in window!");

    [super mouseUp:theEvent];
}

1 Ответ

0 голосов
/ 24 марта 2010

Как я могу отправлять [somePopUpMenu cancelTracking], когда пользователь переходит к следующей кнопке?

Делать именно это. NSMenu отвечает на cancelTracking сообщение , начиная с Mac OS X 10.5.

...