プログラムでNSRunAlertPanel()を呼び出すと、戻るのを待っている間(ユーザーがまだボタンをクリックしていない)、NSTimer()が起動しないことに気付きました。NSRunAlertPanel()行まで完全に定期的に起動しますが、ユーザーがダイアログのボタンをクリックするまで再度呼び出されることはありません。
ダイアログが画面に表示されている間でも、タイマーを実行し続ける方法はありますか?
プログラムでNSRunAlertPanel()を呼び出すと、戻るのを待っている間(ユーザーがまだボタンをクリックしていない)、NSTimer()が起動しないことに気付きました。NSRunAlertPanel()行まで完全に定期的に起動しますが、ユーザーがダイアログのボタンをクリックするまで再度呼び出されることはありません。
ダイアログが画面に表示されている間でも、タイマーを実行し続ける方法はありますか?
-[NSApplication runModalForWindow:]
アラートパネルは、タイマーが最初にスケジュールされた(おそらくメインの)イベントループとは別に、独自のイベントループを開始しています。これは、アラートが処理されるまで、ユーザーがアプリケーションの他の要素と対話できないようにするためです。
パネルが表示されている間もタイマーを起動させるには、2つの方法が考えられます。メインの実行ループを実行する方法と、パネルの実行ループにタイマーを追加する方法です。正直なところ、これらのどちらがうまくいくかはわかりません。
最初に、アプリケーションのメイン実行ループを簡単に取得できます。次に、将来、短時間(1秒未満)に実行する[NSRunLoop mainRunLoop]
ように指示します。runUntilDate:
これには、()ループを設定する必要があります。この場合while
、メイン実行ループとモーダル実行ループを短時間交互に実行します。ここでの問題は、メイン実行ループをアクティブにすると、入力が処理され、パネルのモダリティが無効になることです。
2つ目は、タイマーへの参照を取得してから実行します[[NSRunLoop currentRunLoop] addTimer:forMode:]
。ここでよくわからないのは、タイマーの起動日が別のループに再度追加されることとどのように相互作用するかですが、試してみることができます。
うまくいけば、私はばかであり、本当に明白な何かを見逃しています、そして別の答えがすぐに正しい解決策で現れるでしょう。
提案してくれたW'rkncacnterに感謝します!これが私のソリューションのサニタイズされたバージョンです。
画面にタイマーを配置するときは、次を使用します。
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTimer) userInfo:nil repeats:YES];
これにより、毎秒次のコードが呼び出されます。
- (void) updateTimer {
secondsRemaining--;
if (secondsRemaining <= 0) {
[timer invalidate];
[[NSApplication sharedApplication] abortModal];
[self finishStuff];
}
[self updateTimerText];
}
- (void) updateTimerText {
NSInteger seconds = (int) secondsRemaining;
NSInteger hours = seconds / (60 * 60);
seconds -= hours * (60 * 60);
NSInteger minutes = seconds / 60;
seconds -= minutes * 60;
[timerText setStringValue:[NSString stringWithFormat:@"%02ld:%02ld:%02ld", hours, minutes, seconds]];
}
「abortModal」コードに注意してください。タイマーが切れたときにNSRunAlertPanel()が開いている場合、タイマーは閉じられます。ダイアログを表示したいときは、次のコードを実行します。
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSModalPanelRunLoopMode];
NSInteger buttonClicked = NSRunAlertPanel(@"Finish?", @"Are you sure you are done?", @"No", @"Yes", nil);
//"YES" clicked
if (buttonClicked == NSAlertAlternateReturn) {
[timer invalidate];
[self finishStuff];
}
今回は、モーダルウィンドウ用の別の実行ループにタイマーを再度追加していることに注意してください。タイマーはまだ元の実行ループ上にあり、ダイアログが閉じられても続行されます。