Можно ли использовать NSAlert для создания плавающего окна?

StackOverflow https://stackoverflow.com/questions/765416

  •  12-09-2019
  •  | 
  •  

Вопрос

У меня есть приложение 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];
}

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

Есть ли что-нибудь еще, что мне следовало сделать?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top