Можно ли использовать 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 просто не соблюдает ни одну из этих настроек.


person Kristopher Johnson    schedule 19.04.2009    source источник
comment
всякий раз, когда вызывается runModal, он сбрасывает уровень окна, не уверен, что это помогает...   -  person cobbal    schedule 19.04.2009


Ответы (2)


Я разрушил свой мозг об этой конкретной вещи некоторое время назад.

Единственный способ, которым я мог заставить это работать (вроде), состоял в том, чтобы создать подкласс 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. Если вас действительно волнует эта возможность, я бы зарегистрировал ошибку. Довольно странно, что [[alert window] setLevel: someLevel] не соблюдается NSApplication, и было бы напрасно пересобирать NSAlert со всеми его изящными небольшими функциями автоматического макета только для того, чтобы иметь возможность сделать это.

person Dirk Stoop    schedule 19.04.2009

В итоге я отказался от NSAlert и вместо этого загрузил бдительный NSWindow из NIB.

Вот код, который отображает окно:

- (void)showAlert {
    NSWindow *w = [self window];
    [w makeFirstResponder:nil];
    [w setLevel:NSFloatingWindowLevel];
    [w center];
    [w makeKeyAndOrderFront:self];
}

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

Есть ли что-то еще, что я должен был сделать?

person Kristopher Johnson    schedule 21.04.2009