Можно ли использовать NSAlert для создания плавающего окна?
Вопрос
У меня есть приложение Cocoa, которое отображает модальное оповещение приложения с помощью NSAlert
сорт.Я бы хотел, чтобы окно оповещения располагалось над окнами всех других приложений.Можно ли это сделать с NSAlert
, или мне нужно реализовать собственное окно?
Не знаю, имеет ли это значение, но приложение является агентским (LSUIElement
верно) реализовано как NSStatusItem
.(Дополнительную информацию о приложении, включая исходный код, см. <здесь>.)
Вот код, который отображает предупреждение:
- (void)showTimerExpiredAlert {
[NSApp activateIgnoringOtherApps:YES];
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:NSInformationalAlertStyle];
[alert setMessageText:NSLocalizedString(@"Menubar Countdown Complete", @"Expiration message")];
[alert setInformativeText:NSLocalizedString(@"The countdown timer has reached 00:00:00.",
@"Expiration information")];
[alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK button title")];
[alert addButtonWithTitle:NSLocalizedString(@"Restart Countdown...", @"Restart button title")];
NSInteger clickedButton = [alert runModal];
[alert release];
if (clickedButton == NSAlertSecondButtonReturn) {
// ...
}
}
Я попробовал поставить это перед runModal
вызов:
[[alert window] setFloatingPanel:YES];
Я также пробовал это:
[[alert window] setLevel:NSFloatingWindowLevel];
Но ни один из них не заставляет окно оставаться выше других, если я нажимаю на окно другого приложения.Я подозреваю runModal
просто не соблюдает ни одну из этих настроек.
Решение
Некоторое время назад я сломал себе мозг именно об этом.
Единственный способ заставить это работать (вроде как) — создать подкласс NSApplication и переопределить -sendEvent.В -sendEvent вы сначала вызываете реализацию super, а затем делаете что-то вроде этого:
id *modalWindow = [self modalWindow];
if (modalWindow && [modalWindow level] != MY_DESIRED_MODAL_WINDOW_LEVEL)
[modalWindow setLevel: MY_DESIRED_MODAL_WINDOW_LEVEL];
Кроме того, даже это работало не совсем безупречно — при переключении приложений вы все равно никогда не захотите этого делать, потому что это вопиющий и грубый хак.
Так что да, к сожалению, вам лучше написать свою собственную версию NSAlert.Если вас действительно волнует такая возможность, я бы сообщил об ошибке.Довольно странно, что [[окно оповещения] setLevel:someLevel] не поддерживается NSApplication, и было бы напрасной тратой времени пересоздавать NSAlert со всеми его аккуратными маленькими функциями автоматической компоновки только для того, чтобы иметь возможность сделать это.
Другие советы
В итоге я бросил NSAlert
и вместо этого я загружаю оповещение NSWindow
из СИБ.
Вот код, который отображает окно:
- (void)showAlert {
NSWindow *w = [self window];
[w makeFirstResponder:nil];
[w setLevel:NSFloatingWindowLevel];
[w center];
[w makeKeyAndOrderFront:self];
}
Это предназначено для того, чтобы оно действовало как предупреждение, за исключением того, что оно также является плавающим и не является модальным, поэтому элементы меню можно выбирать, пока оно открыто.
Есть ли что-нибудь еще, что мне следовало сделать?