Блокировать до тех пор, пока NSAlert (показанный в виде модального листа) не будет удален - PullRequest
0 голосов
/ 10 ноября 2011

В настоящее время я изучаю (выполняя) target-c путем реализации функции, которая, по моему мнению, отсутствует в Titanium Appcelerator Desktop SDK: способ создания модального диалога с текстами пользовательских кнопок и, при необходимости, для отображения их в виде «листа».

Все отлично и работает, однако, при отображении NSAlert в виде "листа" мой метод, который создает предупреждение, немедленно возвращается, и это то, что я хочу предотвратить.

Метод создаетalert возвращает int (код возврата из NSAlert).

Код внутри в основном сводится к:

int returnCode = -1;
if (displayAsSheet) {
    [alert beginSheetModalForWindow:nativeWindow modalDelegate:delegate didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];

} else {
    returnCode = [alert runModal];
}

return returnCode;

modalDelegate - это объект, реализующий необходимое:

- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo;

и сейчас он просто выполняет NSLog returnCode.

Итак, мой вопрос:

Как я могу заблокировать возврат моего метода до тех пор, пока «лист» не будет отклонен?

Или я поступаю неправильно?

Ответы [ 5 ]

4 голосов
/ 10 ноября 2011

Вы должны начать модальный сеанс для своего листа после его показа и остановить сеанс после закрытия листа.

Проверьте это: https://github.com/incbee/NSAlert-SynchronousSheet, Я думаю, что это будет полезно.

1 голос
/ 10 ноября 2011

мой метод создания оповещения немедленно возвращается

Я полагаю, это потому, что, как говорит @Josh, лист работает модально только относительно окна, к которому он прикреплен; это не замораживает все приложение. Поэтому, как только beginSheetModal... выполняется, остальная часть вашего метода продолжает выполняться, заканчивая return returnCode (здесь возвращается -1), не дожидаясь ответа пользователя на предупреждение.

Код возврата является заменой, для которой кнопка на панели оповещений, которую пользователь заканчивает нажатием (NSAlertFirstButtonReturn, NSAlertSecondButtonReturn и т. Д. - они перечислены в конце класса NSAlert ref ). Вы используете его в своем методе alertDidEnd, чтобы воздействовать на любую кнопку, которую пользователь нажал, чтобы отключить предупреждение. Вот почему селектор alertDidEnd включает код возврата.

С другой стороны, когда вы используете метод runModal в своем блоке else, вам нужно явно вызвать alertDidEnd и передать ему число, возвращаемое, когда заканчивается метод runModal - когда пользователь отклоняет предупреждение.

Вот пересмотренная версия вашего кода:

int returnCode = -1;
if (displayAsSheet) {
    [alert beginSheetModalForWindow:nativeWindow modalDelegate:delegate didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
    // The selector alertDidEnd has the returnCode int. The alert will then set that code to whatever the user chooses, and will send the altered int on to alertDidEnd.
} 
else {
    // Here, everything stops once runModal is called, until the user dismisses the alert, at which time the runModal method returns the int representing the button the user pushed, and you assign the return to your variable "returnCode."
    returnCode = [alert runModal];
    [self alertDidEnd:alert returnCode:returnCode contextInfo:nil];
}
// Omit the line returning the returnCode.

Тогда метод alertDidEnd делает что-то вроде этого:

- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { 
switch (returnCode) {
    case NSAlertFirstButtonReturn:
        // Do whatever should happen when first button is pushed.
        break;
    case NSAlertSecondButtonReturn: 
        // Do whatever should happen when second button is pushed.
        break;
    default:
        break;
    }
    // Unfreeze things.
    [[NSApplication sharedApplication] stopModal];
}

Кстати, - это способ запуска листа и замораживания всего приложения, а не только окна, к которому прикреплен лист, если вы этого хотите: модальные подсказки

1 голос
/ 10 ноября 2011

Вы можете использовать это после beginSheetModalForWindow:...:

[[NSRunLoop mainRunLoop] runMode:NSModalPanelRunLoopMode beforeDate:[NSDate distantFuture]]

Однако любые другие окна в вашем приложении будут недоступны до тех пор, пока лист не будет отклонен. Было бы лучше не блокировать эти окна.

0 голосов
/ 10 ноября 2011

Вы можете попробовать установить логическое значение, которое замораживает все, что вы хотите заморозить в вашем приложении (установить замораживание = ДА) до тех пор, пока лист не будет удален (установить замораживание = НЕТ).
В общем случае вам не нужно блокировать метод: вы просто хотите, чтобы некоторые вещи не происходили, пока пользователь не сделал выбор.

Например, у меня есть приложение, которое использует гироскоп. Это имеет некоторое поведение с, и некоторое другое поведение без.
Таким образом, у меня есть логическое значение, которое используется в любом методе, который использует гироскопические данные для направления поведения к хорошему. My useGyro Boolean - НЕТ, когда: пользователь выбирает, какую аппаратную функцию он хочет включить или нет, и когда гироскоп недоступен на устройстве.

То же самое с mapView, который у меня есть: когда пользователь запрашивает систему, если он хочет быть найден, наступает момент, когда я замораживаю любое поведение, используя местоположение пользователя. Когда он сделал свой выбор, я изменяю это значение bool.

0 голосов
/ 10 ноября 2011

Вы думаете об этом немного неправильно.Если бы ваш метод смог дождаться окончания листа, цикл событий приложения был бы заблокирован, и у пользователя не было бы возможности взаимодействовать с пользовательским интерфейсом.Когда вы используете runModal для оповещения, для обработки оповещения создается новый цикл выполнения - вот почему больше ничего нельзя сделать с приложением.Суть опции листа заключается в том, чтобы позволить пользователю делать другие вещи во время отображения предупреждения, т. Е. Оно явно не берет на себя обработку события.

Вы можете посмотреть вподделка листа путем прикрепления дочернего окна.

...