Как Apple обновляет меню Airport, в то время как это открыто? (Как изменить NSMenu, когда это уже открыто),

У меня есть объект строки состояния, который появляется, открывают NSMenu, и мне установили делегата, и он поднят трубку правильно (-(void)menuNeedsUpdate:(NSMenu *)menu хорошо работает). Тем не менее тот метод является установкой, которую назовут, прежде чем меню будет отображено, я должен прислушаться к этому и инициировать асинхронный запрос, позже обновив меню, в то время как это открыто, и я не могу выяснить, как это, как предполагается, сделано.

Спасибо :)

Править

Хорошо, я теперь здесь:

При нажатии на пункт меню (в строке состояния), селектор называют, который выполняет NSTask. Я использую центр уведомления для прислушиваний, когда та задача закончена, и запишите:

[[NSRunLoop currentRunLoop] performSelector:@selector(updateTheMenu:) target:self argument:statusBarMenu order:0 modes:[NSArray arrayWithObject:NSEventTrackingRunLoopMode]];

и имейте:

- (void)updateTheMenu:(NSMenu*)menu {
    NSMenuItem *mitm = [[NSMenuItem alloc] init];
    [mitm setEnabled:NO];
    [mitm setTitle:@"Bananas"];
    [mitm setIndentationLevel:2];
    [menu insertItem:mitm atIndex:2];
    [mitm release];
}

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

34
задан Quinn Taylor 26 April 2013 в 18:36
поделиться

2 ответа

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

Ключ - [NSMenuItem setAlternate:] . Например, предположим, что мы собираемся создать NSMenu , в котором есть действие Сделать что-нибудь ... . Вы бы запрограммировали это как что-то вроде:

NSMenu * m = [[NSMenu alloc] init];

NSMenuItem * doSomethingPrompt = [m addItemWithTitle:@"Do something..." action:@selector(doSomethingPrompt:) keyEquivalent:@"d"];
[doSomethingPrompt setTarget:self];
[doSomethingPrompt setKeyEquivalentModifierMask:NSShiftKeyMask];

NSMenuItem * doSomething = [m addItemWithTitle:@"Do something" action:@selector(doSomething:) keyEquivalent:@"d"];
[doSomething setTarget:self];
[doSomething setKeyEquivalentModifierMask:(NSShiftKeyMask | NSAlternateKeyMask)];
[doSomething setAlternate:YES];

//do something with m

Теперь вы можете подумать, что это создаст меню с двумя элементами в нем: «Сделайте что-нибудь ...» и «Сделайте что-нибудь», и вы будете частично Правильно. Поскольку мы устанавливаем второй пункт меню как альтернативный, и поскольку оба пункта меню имеют одинаковый ключевой эквивалент (но разные маски модификаторов), то только первый (то есть тот, который по умолчанию setAlternate: NO ) покажет. Затем, когда у вас открыто меню, если вы нажмете маску модификатора, которая представляет вторую (т. Е. Клавишу выбора), тогда элемент меню будет преобразовываться в реальном времени из первого элемента меню во второй.

Так, например, работает меню Apple. Если вы щелкните по нему один раз, вы увидите несколько вариантов с многоточием после них, например «Перезагрузить ...» и «Завершение работы ...». HIG указывает, что наличие многоточия означает, что система запросит у пользователя подтверждение перед выполнением действия. Однако, если вы нажмете клавишу выбора (при все еще открытом меню), вы заметите, что они меняются на «Перезагрузка» и «Завершение работы».Эллипсы исчезнут, что означает, что если вы выберете их при нажатой клавише выбора, они будут выполнены немедленно, без запроса подтверждения у пользователя.

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

14
ответ дан 27 November 2019 в 17:04
поделиться

Отслеживание мыши в меню выполняется в специальном режиме цикла выполнения (NSEventTrackingRunLoopMode). Чтобы изменить меню, необходимо отправить сообщение так, чтобы оно было обработано в режиме отслеживания событий. Самый простой способ сделать это - использовать метод NSRunLoop:

[[NSRunLoop currentRunLoop] performSelector:@selector(updateTheMenu:) target:self argument:yourMenu order:0 modes:[NSArray arrayWithObject:NSEventTrackingRunLoopMode]]

Вы также можете указать режим как NSRunLoopCommonModes, и сообщение будет отправлено в любом из общих режимов цикла выполнения, включая NSEventTrackingRunLoopMode.

Тогда ваш метод обновления будет работать примерно так:

- (void)updateTheMenu:(NSMenu*)menu
{
    [menu addItemWithTitle:@"Foobar" action:NULL keyEquivalent:@""];
    [menu update];
}
17
ответ дан 27 November 2019 в 17:04
поделиться