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

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

Загвоздка в том, что если я открываю всплывающее меню для кнопки, пользователь должен щелкнуть еще раз, чтобы закрыть ее. Весь цикл выполнения приостановлен, поскольку я считаю, что всплывающее меню является модальным. Как мне получить возможность отправить [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];
}

person hishamk    schedule 22.03.2010    source источник
comment
Как насчет подкласса всплывающей кнопки, переопределения метода mouseEntered: и публикации уведомления для всего приложения?   -  person zonble    schedule 23.03.2010
comment
Проблема в том, что всплывающая кнопка не обрабатывает никаких событий, пока отображается всплывающее меню. Это модально.   -  person hishamk    schedule 23.03.2010
comment
Что появится в консоли отладчика, если вы добавите это к методу stopTimer? NSLog(@"Menu: %p", hookToMenu);   -  person Peter Hosey    schedule 27.03.2010
comment
Я получаю: Menu: ‹NSMenu: 0x200036a00›, и когда я NSLog (@Menu:% @, hookToMenu), я получаю распечатку объекта NSMenu с элементами меню.   -  person hishamk    schedule 27.03.2010
comment
Я получил отказ от меню для работы с помощью недокументированных _NSGetCarbonMenu и CancelMenuTracking (). Это просто кажется странным, что cancelTracking: в Какао не работает в моем случае. Я слышал, что могут быть определенные случаи / условия, когда cancelTracking: не будет работать, но поискав вокруг, я еще не нашел этих неуловимых причин. На данный момент углеродный подход - единственный выход. extern MenuRef _NSGetCarbonMenu (NSMenu *); MenuRef menuRef = _NSGetCarbonMenu (menuToCancel); если (menuToCancel! = NULL) {CancelMenuTracking (menuRef, true, kEventMenuEndTracking); NSLog (@ отклонено через Carbon); }   -  person hishamk    schedule 28.03.2010


Ответы (1)


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

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

person Peter Hosey    schedule 24.03.2010
comment
Я пытался это сделать. Я не могу. Мое приложение не будет обрабатывать дальше, пока отображается всплывающее окно. - person hishamk; 24.03.2010
comment
«Весь цикл выполнения приостановлен, поскольку я считаю, что всплывающее меню является модальным». Нет, он работает в NSEventTrackingRunLoopMode. Если вы запускаете таймер или что-то в этом роде, это режим, в котором его нужно запланировать. - person Peter Hosey; 25.03.2010
comment
Не могли бы вы взглянуть на опубликованный мною код и увидеть, что я делаю не так? Основная проблема в том, что всплывающее окно сохраняется и по какой-то причине не может быть отменено! Я ценю вашу помощь и советы. Спасибо - person hishamk; 27.03.2010